. /** * Library of useful functions * * @copyright 1999 Martin Dougiamas http://dougiamas.com * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package core * @subpackage course */ defined('MOODLE_INTERNAL') || die; require_once($CFG->libdir.'/completionlib.php'); require_once($CFG->libdir.'/filelib.php'); define('COURSE_MAX_LOGS_PER_PAGE', 1000); // records define('COURSE_MAX_RECENT_PERIOD', 172800); // Two days, in seconds define('COURSE_MAX_SUMMARIES_PER_PAGE', 10); // courses define('COURSE_MAX_COURSES_PER_DROPDOWN',1000); // max courses in log dropdown before switching to optional define('COURSE_MAX_USERS_PER_DROPDOWN',1000); // max users in log dropdown before switching to optional define('FRONTPAGENEWS', '0'); define('FRONTPAGECOURSELIST', '1'); define('FRONTPAGECATEGORYNAMES', '2'); define('FRONTPAGETOPICONLY', '3'); define('FRONTPAGECATEGORYCOMBO', '4'); define('FRONTPAGECOURSELIMIT', 200); // maximum number of courses displayed on the frontpage define('EXCELROWS', 65535); define('FIRSTUSEDEXCELROW', 3); define('MOD_CLASS_ACTIVITY', 0); define('MOD_CLASS_RESOURCE', 1); function make_log_url($module, $url) { switch ($module) { case 'course': if (strpos($url, 'report/') === 0) { // there is only one report type, course reports are deprecated $url = "/$url"; break; } case 'file': case 'login': case 'lib': case 'admin': case 'calendar': case 'mnet course': if (strpos($url, '../') === 0) { $url = ltrim($url, '.'); } else { $url = "/course/$url"; } break; case 'user': case 'blog': $url = "/$module/$url"; break; case 'upload': $url = $url; break; case 'coursetags': $url = '/'.$url; break; case 'library': case '': $url = '/'; break; case 'message': $url = "/message/$url"; break; case 'notes': $url = "/notes/$url"; break; case 'tag': $url = "/tag/$url"; break; case 'role': $url = '/'.$url; break; default: $url = "/mod/$module/$url"; break; } //now let's sanitise urls - there might be some ugly nasties:-( $parts = explode('?', $url); $script = array_shift($parts); if (strpos($script, 'http') === 0) { $script = clean_param($script, PARAM_URL); } else { $script = clean_param($script, PARAM_PATH); } $query = ''; if ($parts) { $query = implode('', $parts); $query = str_replace('&', '&', $query); // both & and & are stored in db :-| $parts = explode('&', $query); $eq = urlencode('='); foreach ($parts as $key=>$part) { $part = urlencode(urldecode($part)); $part = str_replace($eq, '=', $part); $parts[$key] = $part; } $query = '?'.implode('&', $parts); } return $script.$query; } function build_mnet_logs_array($hostid, $course, $user=0, $date=0, $order="l.time ASC", $limitfrom='', $limitnum='', $modname="", $modid=0, $modaction="", $groupid=0) { global $CFG, $DB; // It is assumed that $date is the GMT time of midnight for that day, // and so the next 86400 seconds worth of logs are printed. /// Setup for group handling. // TODO: I don't understand group/context/etc. enough to be able to do // something interesting with it here // What is the context of a remote course? /// If the group mode is separate, and this user does not have editing privileges, /// then only the user's group can be viewed. //if ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) { // $groupid = get_current_group($course->id); //} /// If this course doesn't have groups, no groupid can be specified. //else if (!$course->groupmode) { // $groupid = 0; //} $groupid = 0; $joins = array(); $where = ''; $qry = "SELECT l.*, u.firstname, u.lastname, u.picture FROM {mnet_log} l LEFT JOIN {user} u ON l.userid = u.id WHERE "; $params = array(); $where .= "l.hostid = :hostid"; $params['hostid'] = $hostid; // TODO: Is 1 really a magic number referring to the sitename? if ($course != SITEID || $modid != 0) { $where .= " AND l.course=:courseid"; $params['courseid'] = $course; } if ($modname) { $where .= " AND l.module = :modname"; $params['modname'] = $modname; } if ('site_errors' === $modid) { $where .= " AND ( l.action='error' OR l.action='infected' )"; } else if ($modid) { //TODO: This assumes that modids are the same across sites... probably //not true $where .= " AND l.cmid = :modid"; $params['modid'] = $modid; } if ($modaction) { $firstletter = substr($modaction, 0, 1); if ($firstletter == '-') { $where .= " AND ".$DB->sql_like('l.action', ':modaction', false, true, true); $params['modaction'] = '%'.substr($modaction, 1).'%'; } else { $where .= " AND ".$DB->sql_like('l.action', ':modaction', false); $params['modaction'] = '%'.$modaction.'%'; } } if ($user) { $where .= " AND l.userid = :user"; $params['user'] = $user; } if ($date) { $enddate = $date + 86400; $where .= " AND l.time > :date AND l.time < :enddate"; $params['date'] = $date; $params['enddate'] = $enddate; } $result = array(); $result['totalcount'] = $DB->count_records_sql("SELECT COUNT('x') FROM {mnet_log} l WHERE $where", $params); if(!empty($result['totalcount'])) { $where .= " ORDER BY $order"; $result['logs'] = $DB->get_records_sql("$qry $where", $params, $limitfrom, $limitnum); } else { $result['logs'] = array(); } return $result; } function build_logs_array($course, $user=0, $date=0, $order="l.time ASC", $limitfrom='', $limitnum='', $modname="", $modid=0, $modaction="", $groupid=0) { global $DB, $SESSION, $USER; // It is assumed that $date is the GMT time of midnight for that day, // and so the next 86400 seconds worth of logs are printed. /// Setup for group handling. /// If the group mode is separate, and this user does not have editing privileges, /// then only the user's group can be viewed. if ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) { if (isset($SESSION->currentgroup[$course->id])) { $groupid = $SESSION->currentgroup[$course->id]; } else { $groupid = groups_get_all_groups($course->id, $USER->id); if (is_array($groupid)) { $groupid = array_shift(array_keys($groupid)); $SESSION->currentgroup[$course->id] = $groupid; } else { $groupid = 0; } } } /// If this course doesn't have groups, no groupid can be specified. else if (!$course->groupmode) { $groupid = 0; } $joins = array(); $params = array(); if ($course->id != SITEID || $modid != 0) { $joins[] = "l.course = :courseid"; $params['courseid'] = $course->id; } if ($modname) { $joins[] = "l.module = :modname"; $params['modname'] = $modname; } if ('site_errors' === $modid) { $joins[] = "( l.action='error' OR l.action='infected' )"; } else if ($modid) { $joins[] = "l.cmid = :modid"; $params['modid'] = $modid; } if ($modaction) { $firstletter = substr($modaction, 0, 1); if ($firstletter == '-') { $joins[] = $DB->sql_like('l.action', ':modaction', false, true, true); $params['modaction'] = '%'.substr($modaction, 1).'%'; } else { $joins[] = $DB->sql_like('l.action', ':modaction', false); $params['modaction'] = '%'.$modaction.'%'; } } /// Getting all members of a group. if ($groupid and !$user) { if ($gusers = groups_get_members($groupid)) { $gusers = array_keys($gusers); $joins[] = 'l.userid IN (' . implode(',', $gusers) . ')'; } else { $joins[] = 'l.userid = 0'; // No users in groups, so we want something that will always be false. } } else if ($user) { $joins[] = "l.userid = :userid"; $params['userid'] = $user; } if ($date) { $enddate = $date + 86400; $joins[] = "l.time > :date AND l.time < :enddate"; $params['date'] = $date; $params['enddate'] = $enddate; } $selector = implode(' AND ', $joins); $totalcount = 0; // Initialise $result = array(); $result['logs'] = get_logs($selector, $params, $order, $limitfrom, $limitnum, $totalcount); $result['totalcount'] = $totalcount; return $result; } function print_log($course, $user=0, $date=0, $order="l.time ASC", $page=0, $perpage=100, $url="", $modname="", $modid=0, $modaction="", $groupid=0) { global $CFG, $DB, $OUTPUT; if (!$logs = build_logs_array($course, $user, $date, $order, $page*$perpage, $perpage, $modname, $modid, $modaction, $groupid)) { echo $OUTPUT->notification("No logs found!"); echo $OUTPUT->footer(); exit; } $courses = array(); if ($course->id == SITEID) { $courses[0] = ''; if ($ccc = get_courses('all', 'c.id ASC', 'c.id,c.shortname')) { foreach ($ccc as $cc) { $courses[$cc->id] = $cc->shortname; } } } else { $courses[$course->id] = $course->shortname; } $totalcount = $logs['totalcount']; $count=0; $ldcache = array(); $tt = getdate(time()); $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]); $strftimedatetime = get_string("strftimedatetime"); echo "
\n"; print_string("displayingrecords", "", $totalcount); echo "
\n"; echo $OUTPUT->paging_bar($totalcount, $page, $perpage, "$url&perpage=$perpage"); $table = new html_table(); $table->classes = array('logtable','generalbox'); $table->align = array('right', 'left', 'left'); $table->head = array( get_string('time'), get_string('ip_address'), get_string('fullnameuser'), get_string('action'), get_string('info') ); $table->data = array(); if ($course->id == SITEID) { array_unshift($table->align, 'left'); array_unshift($table->head, get_string('course')); } // Make sure that the logs array is an array, even it is empty, to avoid warnings from the foreach. if (empty($logs['logs'])) { $logs['logs'] = array(); } foreach ($logs['logs'] as $log) { if (isset($ldcache[$log->module][$log->action])) { $ld = $ldcache[$log->module][$log->action]; } else { $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action)); $ldcache[$log->module][$log->action] = $ld; } if ($ld && is_numeric($log->info)) { // ugly hack to make sure fullname is shown correctly if ($ld->mtable == 'user' && $ld->field == $DB->sql_concat('firstname', "' '" , 'lastname')) { $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true); } else { $log->info = $DB->get_field($ld->mtable, $ld->field, array('id'=>$log->info)); } } //Filter log->info $log->info = format_string($log->info); // If $log->url has been trimmed short by the db size restriction // code in add_to_log, keep a note so we don't add a link to a broken url $tl=textlib_get_instance(); $brokenurl=($tl->strlen($log->url)==100 && $tl->substr($log->url,97)=='...'); $row = array(); if ($course->id == SITEID) { if (empty($log->course)) { $row[] = get_string('site'); } else { $row[] = "wwwroot}/course/view.php?id={$log->course}\">". format_string($courses[$log->course]).""; } } $row[] = userdate($log->time, '%a').' '.userdate($log->time, $strftimedatetime); $link = new moodle_url("/iplookup/index.php?ip=$log->ip&user=$log->userid"); $row[] = $OUTPUT->action_link($link, $log->ip, new popup_action('click', $link, 'iplookup', array('height' => 440, 'width' => 700))); $row[] = html_writer::link(new moodle_url("/user/view.php?id={$log->userid}&course={$log->course}"), fullname($log, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $course->id)))); $displayaction="$log->module $log->action"; if ($brokenurl) { $row[] = $displayaction; } else { $link = make_log_url($log->module,$log->url); $row[] = $OUTPUT->action_link($link, $displayaction, new popup_action('click', $link, 'fromloglive'), array('height' => 440, 'width' => 700)); } $row[] = $log->info; $table->data[] = $row; } echo html_writer::table($table); echo $OUTPUT->paging_bar($totalcount, $page, $perpage, "$url&perpage=$perpage"); } function print_mnet_log($hostid, $course, $user=0, $date=0, $order="l.time ASC", $page=0, $perpage=100, $url="", $modname="", $modid=0, $modaction="", $groupid=0) { global $CFG, $DB, $OUTPUT; if (!$logs = build_mnet_logs_array($hostid, $course, $user, $date, $order, $page*$perpage, $perpage, $modname, $modid, $modaction, $groupid)) { echo $OUTPUT->notification("No logs found!"); echo $OUTPUT->footer(); exit; } if ($course->id == SITEID) { $courses[0] = ''; if ($ccc = get_courses('all', 'c.id ASC', 'c.id,c.shortname,c.visible')) { foreach ($ccc as $cc) { $courses[$cc->id] = $cc->shortname; } } } $totalcount = $logs['totalcount']; $count=0; $ldcache = array(); $tt = getdate(time()); $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]); $strftimedatetime = get_string("strftimedatetime"); echo "
\n"; print_string("displayingrecords", "", $totalcount); echo "
\n"; echo $OUTPUT->paging_bar($totalcount, $page, $perpage, "$url&perpage=$perpage"); echo "\n"; echo ""; if ($course->id == SITEID) { echo "\n"; } echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n"; echo "\n"; if (empty($logs['logs'])) { echo "
".get_string('course')."".get_string('time')."".get_string('ip_address')."".get_string('fullnameuser')."".get_string('action')."".get_string('info')."
\n"; return; } $row = 1; foreach ($logs['logs'] as $log) { $log->info = $log->coursename; $row = ($row + 1) % 2; if (isset($ldcache[$log->module][$log->action])) { $ld = $ldcache[$log->module][$log->action]; } else { $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action)); $ldcache[$log->module][$log->action] = $ld; } if (0 && $ld && !empty($log->info)) { // ugly hack to make sure fullname is shown correctly if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) { $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true); } else { $log->info = $DB->get_field($ld->mtable, $ld->field, array('id'=>$log->info)); } } //Filter log->info $log->info = format_string($log->info); echo ''; if ($course->id == SITEID) { $courseshortname = format_string($courses[$log->course], true, array('context' => get_context_instance(CONTEXT_COURSE, SITEID))); echo "\n"; echo " wwwroot}/course/view.php?id={$log->course}\">".$courseshortname."\n"; echo "\n"; } echo "".userdate($log->time, '%a'). ' '.userdate($log->time, $strftimedatetime)."\n"; echo "\n"; $link = new moodle_url("/iplookup/index.php?ip=$log->ip&user=$log->userid"); echo $OUTPUT->action_link($link, $log->ip, new popup_action('click', $link, 'iplookup', array('height' => 400, 'width' => 700))); echo "\n"; $fullname = fullname($log, has_capability('moodle/site:viewfullnames', get_context_instance(CONTEXT_COURSE, $course->id))); echo "\n"; echo " wwwroot/user/view.php?id={$log->userid}\">$fullname\n"; echo "\n"; echo "\n"; echo $log->action .': '.$log->module; echo "\n";; echo "{$log->info}\n"; echo "\n"; } echo "\n"; echo $OUTPUT->paging_bar($totalcount, $page, $perpage, "$url&perpage=$perpage"); } function print_log_csv($course, $user, $date, $order='l.time DESC', $modname, $modid, $modaction, $groupid) { global $DB; $text = get_string('course')."\t".get_string('time')."\t".get_string('ip_address')."\t". get_string('fullnameuser')."\t".get_string('action')."\t".get_string('info'); if (!$logs = build_logs_array($course, $user, $date, $order, '', '', $modname, $modid, $modaction, $groupid)) { return false; } $courses = array(); if ($course->id == SITEID) { $courses[0] = ''; if ($ccc = get_courses('all', 'c.id ASC', 'c.id,c.shortname')) { foreach ($ccc as $cc) { $courses[$cc->id] = $cc->shortname; } } } else { $courses[$course->id] = $course->shortname; } $count=0; $ldcache = array(); $tt = getdate(time()); $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]); $strftimedatetime = get_string("strftimedatetime"); $filename = 'logs_'.userdate(time(),get_string('backupnameformat', 'langconfig'),99,false); $filename .= '.txt'; header("Content-Type: application/download\n"); header("Content-Disposition: attachment; filename=$filename"); header("Expires: 0"); header("Cache-Control: must-revalidate,post-check=0,pre-check=0"); header("Pragma: public"); echo get_string('savedat').userdate(time(), $strftimedatetime)."\n"; echo $text."\n"; if (empty($logs['logs'])) { return true; } foreach ($logs['logs'] as $log) { if (isset($ldcache[$log->module][$log->action])) { $ld = $ldcache[$log->module][$log->action]; } else { $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action)); $ldcache[$log->module][$log->action] = $ld; } if ($ld && !empty($log->info)) { // ugly hack to make sure fullname is shown correctly if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) { $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true); } else { $log->info = $DB->get_field($ld->mtable, $ld->field, array('id'=>$log->info)); } } //Filter log->info $log->info = format_string($log->info); $log->info = strip_tags(urldecode($log->info)); // Some XSS protection $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); $firstField = format_string($courses[$log->course], true, array('context' => $coursecontext)); $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext)); $row = array($firstField, userdate($log->time, $strftimedatetime), $log->ip, $fullname, $log->module.' '.$log->action, $log->info); $text = implode("\t", $row); echo $text." \n"; } return true; } function print_log_xls($course, $user, $date, $order='l.time DESC', $modname, $modid, $modaction, $groupid) { global $CFG, $DB; require_once("$CFG->libdir/excellib.class.php"); if (!$logs = build_logs_array($course, $user, $date, $order, '', '', $modname, $modid, $modaction, $groupid)) { return false; } $courses = array(); if ($course->id == SITEID) { $courses[0] = ''; if ($ccc = get_courses('all', 'c.id ASC', 'c.id,c.shortname')) { foreach ($ccc as $cc) { $courses[$cc->id] = $cc->shortname; } } } else { $courses[$course->id] = $course->shortname; } $count=0; $ldcache = array(); $tt = getdate(time()); $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]); $strftimedatetime = get_string("strftimedatetime"); $nroPages = ceil(count($logs)/(EXCELROWS-FIRSTUSEDEXCELROW+1)); $filename = 'logs_'.userdate(time(),get_string('backupnameformat', 'langconfig'),99,false); $filename .= '.xls'; $workbook = new MoodleExcelWorkbook('-'); $workbook->send($filename); $worksheet = array(); $headers = array(get_string('course'), get_string('time'), get_string('ip_address'), get_string('fullnameuser'), get_string('action'), get_string('info')); // Creating worksheets for ($wsnumber = 1; $wsnumber <= $nroPages; $wsnumber++) { $sheettitle = get_string('logs').' '.$wsnumber.'-'.$nroPages; $worksheet[$wsnumber] =& $workbook->add_worksheet($sheettitle); $worksheet[$wsnumber]->set_column(1, 1, 30); $worksheet[$wsnumber]->write_string(0, 0, get_string('savedat'). userdate(time(), $strftimedatetime)); $col = 0; foreach ($headers as $item) { $worksheet[$wsnumber]->write(FIRSTUSEDEXCELROW-1,$col,$item,''); $col++; } } if (empty($logs['logs'])) { $workbook->close(); return true; } $formatDate =& $workbook->add_format(); $formatDate->set_num_format(get_string('log_excel_date_format')); $row = FIRSTUSEDEXCELROW; $wsnumber = 1; $myxls =& $worksheet[$wsnumber]; foreach ($logs['logs'] as $log) { if (isset($ldcache[$log->module][$log->action])) { $ld = $ldcache[$log->module][$log->action]; } else { $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action)); $ldcache[$log->module][$log->action] = $ld; } if ($ld && !empty($log->info)) { // ugly hack to make sure fullname is shown correctly if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) { $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true); } else { $log->info = $DB->get_field($ld->mtable, $ld->field, array('id'=>$log->info)); } } // Filter log->info $log->info = format_string($log->info); $log->info = strip_tags(urldecode($log->info)); // Some XSS protection if ($nroPages>1) { if ($row > EXCELROWS) { $wsnumber++; $myxls =& $worksheet[$wsnumber]; $row = FIRSTUSEDEXCELROW; } } $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); $myxls->write($row, 0, format_string($courses[$log->course], true, array('context' => $coursecontext)), ''); $myxls->write_date($row, 1, $log->time, $formatDate); // write_date() does conversion/timezone support. MDL-14934 $myxls->write($row, 2, $log->ip, ''); $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext)); $myxls->write($row, 3, $fullname, ''); $myxls->write($row, 4, $log->module.' '.$log->action, ''); $myxls->write($row, 5, $log->info, ''); $row++; } $workbook->close(); return true; } function print_log_ods($course, $user, $date, $order='l.time DESC', $modname, $modid, $modaction, $groupid) { global $CFG, $DB; require_once("$CFG->libdir/odslib.class.php"); if (!$logs = build_logs_array($course, $user, $date, $order, '', '', $modname, $modid, $modaction, $groupid)) { return false; } $courses = array(); if ($course->id == SITEID) { $courses[0] = ''; if ($ccc = get_courses('all', 'c.id ASC', 'c.id,c.shortname')) { foreach ($ccc as $cc) { $courses[$cc->id] = $cc->shortname; } } } else { $courses[$course->id] = $course->shortname; } $count=0; $ldcache = array(); $tt = getdate(time()); $today = mktime (0, 0, 0, $tt["mon"], $tt["mday"], $tt["year"]); $strftimedatetime = get_string("strftimedatetime"); $nroPages = ceil(count($logs)/(EXCELROWS-FIRSTUSEDEXCELROW+1)); $filename = 'logs_'.userdate(time(),get_string('backupnameformat', 'langconfig'),99,false); $filename .= '.ods'; $workbook = new MoodleODSWorkbook('-'); $workbook->send($filename); $worksheet = array(); $headers = array(get_string('course'), get_string('time'), get_string('ip_address'), get_string('fullnameuser'), get_string('action'), get_string('info')); // Creating worksheets for ($wsnumber = 1; $wsnumber <= $nroPages; $wsnumber++) { $sheettitle = get_string('logs').' '.$wsnumber.'-'.$nroPages; $worksheet[$wsnumber] =& $workbook->add_worksheet($sheettitle); $worksheet[$wsnumber]->set_column(1, 1, 30); $worksheet[$wsnumber]->write_string(0, 0, get_string('savedat'). userdate(time(), $strftimedatetime)); $col = 0; foreach ($headers as $item) { $worksheet[$wsnumber]->write(FIRSTUSEDEXCELROW-1,$col,$item,''); $col++; } } if (empty($logs['logs'])) { $workbook->close(); return true; } $formatDate =& $workbook->add_format(); $formatDate->set_num_format(get_string('log_excel_date_format')); $row = FIRSTUSEDEXCELROW; $wsnumber = 1; $myxls =& $worksheet[$wsnumber]; foreach ($logs['logs'] as $log) { if (isset($ldcache[$log->module][$log->action])) { $ld = $ldcache[$log->module][$log->action]; } else { $ld = $DB->get_record('log_display', array('module'=>$log->module, 'action'=>$log->action)); $ldcache[$log->module][$log->action] = $ld; } if ($ld && !empty($log->info)) { // ugly hack to make sure fullname is shown correctly if (($ld->mtable == 'user') and ($ld->field == $DB->sql_concat('firstname', "' '" , 'lastname'))) { $log->info = fullname($DB->get_record($ld->mtable, array('id'=>$log->info)), true); } else { $log->info = $DB->get_field($ld->mtable, $ld->field, array('id'=>$log->info)); } } // Filter log->info $log->info = format_string($log->info); $log->info = strip_tags(urldecode($log->info)); // Some XSS protection if ($nroPages>1) { if ($row > EXCELROWS) { $wsnumber++; $myxls =& $worksheet[$wsnumber]; $row = FIRSTUSEDEXCELROW; } } $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); $myxls->write_string($row, 0, format_string($courses[$log->course], true, array('context' => $coursecontext))); $myxls->write_date($row, 1, $log->time); $myxls->write_string($row, 2, $log->ip); $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext)); $myxls->write_string($row, 3, $fullname); $myxls->write_string($row, 4, $log->module.' '.$log->action); $myxls->write_string($row, 5, $log->info); $row++; } $workbook->close(); return true; } function print_overview($courses, array $remote_courses=array()) { global $CFG, $USER, $DB, $OUTPUT; $htmlarray = array(); if ($modules = $DB->get_records('modules')) { foreach ($modules as $mod) { if (file_exists(dirname(dirname(__FILE__)).'/mod/'.$mod->name.'/lib.php')) { include_once(dirname(dirname(__FILE__)).'/mod/'.$mod->name.'/lib.php'); $fname = $mod->name.'_print_overview'; if (function_exists($fname)) { $fname($courses,$htmlarray); } } } } foreach ($courses as $course) { $fullname = format_string($course->fullname, true, array('context' => get_context_instance(CONTEXT_COURSE, $course->id))); echo $OUTPUT->box_start('coursebox'); $attributes = array('title' => s($fullname)); if (empty($course->visible)) { $attributes['class'] = 'dimmed'; } echo $OUTPUT->heading(html_writer::link( new moodle_url('/course/view.php', array('id' => $course->id)), $fullname, $attributes), 3); if (array_key_exists($course->id,$htmlarray)) { foreach ($htmlarray[$course->id] as $modname => $html) { echo $html; } } echo $OUTPUT->box_end(); } if (!empty($remote_courses)) { echo $OUTPUT->heading(get_string('remotecourses', 'mnet')); } foreach ($remote_courses as $course) { echo $OUTPUT->box_start('coursebox'); $attributes = array('title' => s($course->fullname)); echo $OUTPUT->heading(html_writer::link( new moodle_url('/auth/mnet/jump.php', array('hostid' => $course->hostid, 'wantsurl' => '/course/view.php?id='.$course->remoteid)), format_string($course->shortname), $attributes) . ' (' . format_string($course->hostname) . ')', 3); echo $OUTPUT->box_end(); } } /** * This function trawls through the logs looking for * anything new since the user's last login */ function print_recent_activity($course) { // $course is an object global $CFG, $USER, $SESSION, $DB, $OUTPUT; $context = get_context_instance(CONTEXT_COURSE, $course->id); $viewfullnames = has_capability('moodle/site:viewfullnames', $context); $timestart = round(time() - COURSE_MAX_RECENT_PERIOD, -2); // better db caching for guests - 100 seconds if (!isguestuser()) { if (!empty($USER->lastcourseaccess[$course->id])) { if ($USER->lastcourseaccess[$course->id] > $timestart) { $timestart = $USER->lastcourseaccess[$course->id]; } } } echo '
'; echo get_string('activitysince', '', userdate($timestart)); echo '
'; echo '
'; echo ''.get_string('recentactivityreport').''; echo "
\n"; $content = false; /// Firstly, have there been any new enrolments? $users = get_recent_enrolments($course->id, $timestart); //Accessibility: new users now appear in an
    list. if ($users) { echo '
    '; echo $OUTPUT->heading(get_string("newusers").':', 3); $content = true; echo "
      \n"; foreach ($users as $user) { $fullname = fullname($user, $viewfullnames); echo '
    1. wwwroot/user/view.php?id=$user->id&course=$course->id\">$fullname
    2. \n"; } echo "
    \n
    \n"; } /// Next, have there been any modifications to the course structure? $modinfo =& get_fast_modinfo($course); $changelist = array(); $logs = $DB->get_records_select('log', "time > ? AND course = ? AND module = 'course' AND (action = 'add mod' OR action = 'update mod' OR action = 'delete mod')", array($timestart, $course->id), "id ASC"); if ($logs) { $actions = array('add mod', 'update mod', 'delete mod'); $newgones = array(); // added and later deleted items foreach ($logs as $key => $log) { if (!in_array($log->action, $actions)) { continue; } $info = explode(' ', $log->info); // note: in most cases I replaced hardcoding of label with use of // $cm->has_view() but it was not possible to do this here because // we don't necessarily have the $cm for it if ($info[0] == 'label') { // Labels are ignored in recent activity continue; } if (count($info) != 2) { debugging("Incorrect log entry info: id = ".$log->id, DEBUG_DEVELOPER); continue; } $modname = $info[0]; $instanceid = $info[1]; if ($log->action == 'delete mod') { // unfortunately we do not know if the mod was visible if (!array_key_exists($log->info, $newgones)) { $strdeleted = get_string('deletedactivity', 'moodle', get_string('modulename', $modname)); $changelist[$log->info] = array ('operation' => 'delete', 'text' => $strdeleted); } } else { if (!isset($modinfo->instances[$modname][$instanceid])) { if ($log->action == 'add mod') { // do not display added and later deleted activities $newgones[$log->info] = true; } continue; } $cm = $modinfo->instances[$modname][$instanceid]; if (!$cm->uservisible) { continue; } if ($log->action == 'add mod') { $stradded = get_string('added', 'moodle', get_string('modulename', $modname)); $changelist[$log->info] = array('operation' => 'add', 'text' => "$stradded:
    wwwroot/mod/$cm->modname/view.php?id={$cm->id}\">".format_string($cm->name, true).""); } else if ($log->action == 'update mod' and empty($changelist[$log->info])) { $strupdated = get_string('updated', 'moodle', get_string('modulename', $modname)); $changelist[$log->info] = array('operation' => 'update', 'text' => "$strupdated:
    wwwroot/mod/$cm->modname/view.php?id={$cm->id}\">".format_string($cm->name, true).""); } } } } if (!empty($changelist)) { echo $OUTPUT->heading(get_string("courseupdates").':', 3); $content = true; foreach ($changelist as $changeinfo => $change) { echo '

    '.$change['text'].'

    '; } } /// Now display new things from each module $usedmodules = array(); foreach($modinfo->cms as $cm) { if (isset($usedmodules[$cm->modname])) { continue; } if (!$cm->uservisible) { continue; } $usedmodules[$cm->modname] = $cm->modname; } foreach ($usedmodules as $modname) { // Each module gets it's own logs and prints them if (file_exists($CFG->dirroot.'/mod/'.$modname.'/lib.php')) { include_once($CFG->dirroot.'/mod/'.$modname.'/lib.php'); $print_recent_activity = $modname.'_print_recent_activity'; if (function_exists($print_recent_activity)) { // NOTE: original $isteacher (second parameter below) was replaced with $viewfullnames! $content = $print_recent_activity($course, $viewfullnames, $timestart) || $content; } } else { debugging("Missing lib.php in lib/{$modname} - please reinstall files or uninstall the module"); } } if (! $content) { echo '

    '.get_string('nothingnew').'

    '; } } /** * For a given course, returns an array of course activity objects * Each item in the array contains he following properties: */ function get_array_of_activities($courseid) { // cm - course module id // mod - name of the module (eg forum) // section - the number of the section (eg week or topic) // name - the name of the instance // visible - is the instance visible or not // groupingid - grouping id // groupmembersonly - is this instance visible to group members only // extra - contains extra string to include in any link global $CFG, $DB; if(!empty($CFG->enableavailability)) { require_once($CFG->libdir.'/conditionlib.php'); } $course = $DB->get_record('course', array('id'=>$courseid)); if (empty($course)) { throw new moodle_exception('courseidnotfound'); } $mod = array(); $rawmods = get_course_mods($courseid); if (empty($rawmods)) { return $mod; // always return array } if ($sections = $DB->get_records("course_sections", array("course"=>$courseid), "section ASC")) { foreach ($sections as $section) { if (!empty($section->sequence)) { $sequence = explode(",", $section->sequence); foreach ($sequence as $seq) { if (empty($rawmods[$seq])) { continue; } $mod[$seq] = new stdClass(); $mod[$seq]->id = $rawmods[$seq]->instance; $mod[$seq]->cm = $rawmods[$seq]->id; $mod[$seq]->mod = $rawmods[$seq]->modname; // Oh dear. Inconsistent names left here for backward compatibility. $mod[$seq]->section = $section->section; $mod[$seq]->sectionid = $rawmods[$seq]->section; $mod[$seq]->module = $rawmods[$seq]->module; $mod[$seq]->added = $rawmods[$seq]->added; $mod[$seq]->score = $rawmods[$seq]->score; $mod[$seq]->idnumber = $rawmods[$seq]->idnumber; $mod[$seq]->visible = $rawmods[$seq]->visible; $mod[$seq]->visibleold = $rawmods[$seq]->visibleold; $mod[$seq]->groupmode = $rawmods[$seq]->groupmode; $mod[$seq]->groupingid = $rawmods[$seq]->groupingid; $mod[$seq]->groupmembersonly = $rawmods[$seq]->groupmembersonly; $mod[$seq]->indent = $rawmods[$seq]->indent; $mod[$seq]->completion = $rawmods[$seq]->completion; $mod[$seq]->extra = ""; $mod[$seq]->completiongradeitemnumber = $rawmods[$seq]->completiongradeitemnumber; $mod[$seq]->completionview = $rawmods[$seq]->completionview; $mod[$seq]->completionexpected = $rawmods[$seq]->completionexpected; $mod[$seq]->availablefrom = $rawmods[$seq]->availablefrom; $mod[$seq]->availableuntil = $rawmods[$seq]->availableuntil; $mod[$seq]->showavailability = $rawmods[$seq]->showavailability; $mod[$seq]->showdescription = $rawmods[$seq]->showdescription; if (!empty($CFG->enableavailability)) { condition_info::fill_availability_conditions($rawmods[$seq]); $mod[$seq]->conditionscompletion = $rawmods[$seq]->conditionscompletion; $mod[$seq]->conditionsgrade = $rawmods[$seq]->conditionsgrade; } $modname = $mod[$seq]->mod; $functionname = $modname."_get_coursemodule_info"; if (!file_exists("$CFG->dirroot/mod/$modname/lib.php")) { continue; } include_once("$CFG->dirroot/mod/$modname/lib.php"); if ($hasfunction = function_exists($functionname)) { if ($info = $functionname($rawmods[$seq])) { if (!empty($info->icon)) { $mod[$seq]->icon = $info->icon; } if (!empty($info->iconcomponent)) { $mod[$seq]->iconcomponent = $info->iconcomponent; } if (!empty($info->name)) { $mod[$seq]->name = $info->name; } if ($info instanceof cached_cm_info) { // When using cached_cm_info you can include three new fields // that aren't available for legacy code if (!empty($info->content)) { $mod[$seq]->content = $info->content; } if (!empty($info->extraclasses)) { $mod[$seq]->extraclasses = $info->extraclasses; } if (!empty($info->iconurl)) { $mod[$seq]->iconurl = $info->iconurl; } if (!empty($info->onclick)) { $mod[$seq]->onclick = $info->onclick; } if (!empty($info->customdata)) { $mod[$seq]->customdata = $info->customdata; } } else { // When using a stdclass, the (horrible) deprecated ->extra field // is available for BC if (!empty($info->extra)) { $mod[$seq]->extra = $info->extra; } } } } // When there is no modname_get_coursemodule_info function, // but showdescriptions is enabled, then we use the 'intro' // and 'introformat' fields in the module table if (!$hasfunction && $rawmods[$seq]->showdescription) { if ($modvalues = $DB->get_record($rawmods[$seq]->modname, array('id' => $rawmods[$seq]->instance), 'name, intro, introformat')) { // Set content from intro and introformat. Filters are disabled // because we filter it with format_text at display time $mod[$seq]->content = format_module_intro($rawmods[$seq]->modname, $modvalues, $rawmods[$seq]->id, false); // To save making another query just below, put name in here $mod[$seq]->name = $modvalues->name; } } if (!isset($mod[$seq]->name)) { $mod[$seq]->name = $DB->get_field($rawmods[$seq]->modname, "name", array("id"=>$rawmods[$seq]->instance)); } // Minimise the database size by unsetting default options when they are // 'empty'. This list corresponds to code in the cm_info constructor. foreach (array('idnumber', 'groupmode', 'groupingid', 'groupmembersonly', 'indent', 'completion', 'extra', 'extraclasses', 'iconurl', 'onclick', 'content', 'icon', 'iconcomponent', 'customdata', 'showavailability', 'availablefrom', 'availableuntil', 'conditionscompletion', 'conditionsgrade', 'completionview', 'completionexpected', 'score', 'showdescription') as $property) { if (property_exists($mod[$seq], $property) && empty($mod[$seq]->{$property})) { unset($mod[$seq]->{$property}); } } // Special case: this value is usually set to null, but may be 0 if (property_exists($mod[$seq], 'completiongradeitemnumber') && is_null($mod[$seq]->completiongradeitemnumber)) { unset($mod[$seq]->completiongradeitemnumber); } } } } } return $mod; } /** * Returns a number of useful structures for course displays */ function get_all_mods($courseid, &$mods, &$modnames, &$modnamesplural, &$modnamesused) { global $CFG, $DB, $COURSE; $mods = array(); // course modules indexed by id $modnames = array(); // all course module names (except resource!) $modnamesplural= array(); // all course module names (plural form) $modnamesused = array(); // course module names used if ($allmods = $DB->get_records("modules")) { foreach ($allmods as $mod) { if (!file_exists("$CFG->dirroot/mod/$mod->name/lib.php")) { continue; } if ($mod->visible) { $modnames[$mod->name] = get_string("modulename", "$mod->name"); $modnamesplural[$mod->name] = get_string("modulenameplural", "$mod->name"); } } collatorlib::asort($modnames); } else { print_error("nomodules", 'debug'); } $course = ($courseid==$COURSE->id) ? $COURSE : $DB->get_record('course',array('id'=>$courseid)); $modinfo = get_fast_modinfo($course); if ($rawmods=$modinfo->cms) { foreach($rawmods as $mod) { // Index the mods if (empty($modnames[$mod->modname])) { continue; } $mods[$mod->id] = $mod; $mods[$mod->id]->modfullname = $modnames[$mod->modname]; if (!$mod->visible and !has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_COURSE, $courseid))) { continue; } // Check groupings if (!groups_course_module_visible($mod)) { continue; } $modnamesused[$mod->modname] = $modnames[$mod->modname]; } if ($modnamesused) { collatorlib::asort($modnamesused); } } } /** * Returns an array of sections for the requested course id * * This function stores the sections against the course id within a staticvar encase * of subsequent requests. This is used all over + in some standard libs and course * format callbacks so subsequent requests are a reality. * * @staticvar array $coursesections * @param int $courseid * @return array Array of sections */ function get_all_sections($courseid) { global $DB; static $coursesections = array(); if (!array_key_exists($courseid, $coursesections)) { $coursesections[$courseid] = $DB->get_records("course_sections", array("course"=>"$courseid"), "section", "section, id, course, name, summary, summaryformat, sequence, visible"); } return $coursesections[$courseid]; } /** * Returns the course section to display or 0 meaning show all sections. Returns 0 for guests. * It also sets the $USER->display cache to array($courseid=>return value) * * @param int $courseid The course id * @return int Course section to display, 0 means all */ function course_get_display($courseid) { global $USER, $DB; if (!isloggedin() or isguestuser()) { //do not get settings in db for guests return 0; //return the implicit setting } if (!isset($USER->display[$courseid])) { if (!$display = $DB->get_field('course_display', 'display', array('userid' => $USER->id, 'course'=>$courseid))) { $display = 0; // all sections option is not stored in DB, this makes the table much smaller } //use display cache for one course only - we need to keep session small $USER->display = array($courseid => $display); } return $USER->display[$courseid]; } /** * Show one section only or all sections. * * @param int $courseid The course id * @param mixed $display show only this section, 0 or 'all' means show all sections * @return int Course section to display, 0 means all */ function course_set_display($courseid, $display) { global $USER, $DB; if ($display === 'all' or empty($display)) { $display = 0; } if (!isloggedin() or isguestuser()) { //do not store settings in db for guests return 0; } if ($display == 0) { //show all, do not store anything in database $DB->delete_records('course_display', array('userid' => $USER->id, 'course' => $courseid)); } else { if ($DB->record_exists('course_display', array('userid' => $USER->id, 'course' => $courseid))) { $DB->set_field('course_display', 'display', $display, array('userid' => $USER->id, 'course' => $courseid)); } else { $record = new stdClass(); $record->userid = $USER->id; $record->course = $courseid; $record->display = $display; $DB->insert_record('course_display', $record); } } //use display cache for one course only - we need to keep session small $USER->display = array($courseid => $display); return $display; } /** * Set highlighted section. Only one section can be highlighted at the time. * * @param int $courseid course id * @param int $marker highlight section with this number, 0 means remove higlightin * @return void */ function course_set_marker($courseid, $marker) { global $DB; $DB->set_field("course", "marker", $marker, array('id' => $courseid)); } /** * For a given course section, marks it visible or hidden, * and does the same for every activity in that section */ function set_section_visible($courseid, $sectionnumber, $visibility) { global $DB; if ($section = $DB->get_record("course_sections", array("course"=>$courseid, "section"=>$sectionnumber))) { $DB->set_field("course_sections", "visible", "$visibility", array("id"=>$section->id)); if (!empty($section->sequence)) { $modules = explode(",", $section->sequence); foreach ($modules as $moduleid) { set_coursemodule_visible($moduleid, $visibility, true); } } rebuild_course_cache($courseid); } } /** * Obtains shared data that is used in print_section when displaying a * course-module entry. * * Calls format_text or format_string as appropriate, and obtains the correct icon. * * This data is also used in other areas of the code. * @param cm_info $cm Course-module data (must come from get_fast_modinfo) * @param object $course Moodle course object * @return array An array with the following values in this order: * $content (optional extra content for after link), * $instancename (text of link) */ function get_print_section_cm_text(cm_info $cm, $course) { global $OUTPUT; // Get content from modinfo if specified. Content displays either // in addition to the standard link (below), or replaces it if // the link is turned off by setting ->url to null. if (($content = $cm->get_content()) !== '') { // Improve filter performance by preloading filter setttings for all // activities on the course (this does nothing if called multiple // times) filter_preload_activities($cm->get_modinfo()); // Get module context $modulecontext = get_context_instance(CONTEXT_MODULE, $cm->id); $labelformatoptions = new stdClass(); $labelformatoptions->noclean = true; $labelformatoptions->overflowdiv = true; $labelformatoptions->context = $modulecontext; $content = format_text($content, FORMAT_HTML, $labelformatoptions); } else { $content = ''; } // Get course context $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); $stringoptions = new stdClass; $stringoptions->context = $coursecontext; $instancename = format_string($cm->name, true, $stringoptions); return array($content, $instancename); } /** * Prints a section full of activity modules */ function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false) { global $CFG, $USER, $DB, $PAGE, $OUTPUT; static $initialised; static $groupbuttons; static $groupbuttonslink; static $isediting; static $ismoving; static $strmovehere; static $strmovefull; static $strunreadpostsone; static $groupings; static $modulenames; if (!isset($initialised)) { $groupbuttons = ($course->groupmode or (!$course->groupmodeforce)); $groupbuttonslink = (!$course->groupmodeforce); $isediting = $PAGE->user_is_editing(); $ismoving = $isediting && ismoving($course->id); if ($ismoving) { $strmovehere = get_string("movehere"); $strmovefull = strip_tags(get_string("movefull", "", "'$USER->activitycopyname'")); } $modulenames = array(); $initialised = true; } $tl = textlib_get_instance(); $modinfo = get_fast_modinfo($course); $completioninfo = new completion_info($course); //Accessibility: replace table with list