From 70279746ece3d4b4796ef148bb0f44e13e395746 Mon Sep 17 00:00:00 2001 From: Mark Nelson Date: Sun, 9 Mar 2014 18:11:53 -0700 Subject: [PATCH] MDL-41286 report_outline: updated report to use logging api AMOS START MOV [neverseen, mod_folder],[neverseen, report_outline] MOV [neverseen, mod_page],[neverseen, report_outline] MOV [neverseen, mod_resource],[neverseen, report_outline] MOV [neverseen, mod_url],[neverseen, report_outline] AMOS END --- mod/book/lib.php | 41 ---- mod/chat/lib.php | 33 ---- mod/folder/lang/en/folder.php | 1 - mod/folder/lib.php | 51 ----- mod/imscp/lib.php | 51 ----- mod/page/lang/en/page.php | 1 - mod/page/lib.php | 51 ----- mod/resource/lang/en/resource.php | 1 - mod/resource/lib.php | 51 ----- mod/upgrade.txt | 4 + mod/url/lang/en/url.php | 1 - mod/url/lib.php | 51 ----- mod/wiki/lib.php | 26 --- report/outline/index.php | 93 +++++++++- report/outline/lang/en/report_outline.php | 2 + report/outline/locallib.php | 206 +++++++++++++++++++++ report/outline/tests/behat/outline.feature | 109 +++++++++++ report/outline/tests/behat/user.feature | 107 +++++++++++ report/outline/user.php | 35 ++-- 19 files changed, 531 insertions(+), 384 deletions(-) create mode 100644 report/outline/tests/behat/outline.feature create mode 100644 report/outline/tests/behat/user.feature diff --git a/mod/book/lib.php b/mod/book/lib.php index 3eacef55fb8..1139da09f3d 100644 --- a/mod/book/lib.php +++ b/mod/book/lib.php @@ -112,47 +112,6 @@ function book_delete_instance($id) { return true; } -/** - * Return use outline - * - * @param stdClass $course - * @param stdClass $user - * @param stdClass $mod - * @param object $book - * @return object|null - */ -function book_user_outline($course, $user, $mod, $book) { - global $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'book', - 'action'=>'view', 'info'=>$book->id), 'time ASC')) { - - $numviews = count($logs); - $lastlog = array_pop($logs); - - $result = new stdClass(); - $result->info = get_string('numviews', '', $numviews); - $result->time = $lastlog->time; - - return $result; - } - return null; -} - -/** - * Print a detailed representation of what a user has done with - * a given particular instance of this module, for user activity reports. - * - * @param stdClass $course - * @param stdClass $user - * @param stdClass $mod - * @param stdClass $book - * @return bool - */ -function book_user_complete($course, $user, $mod, $book) { - return true; -} - /** * Given a course and a time, this module should find recent activity * that has occurred in book activities and print it out. diff --git a/mod/chat/lib.php b/mod/chat/lib.php index 4a939830884..7fd094a3e7a 100644 --- a/mod/chat/lib.php +++ b/mod/chat/lib.php @@ -203,39 +203,6 @@ function chat_delete_instance($id) { return $result; } -/** - * Return a small object with summary information about what a - * user has done with a given particular instance of this module - * Used for user activity reports. - * - * $return->time = the time they did it - * $return->info = a short text description - * - * - * @param object $course - * @param object $user - * @param object $mod - * @param object $chat - * @return void - */ -function chat_user_outline($course, $user, $mod, $chat) { - return NULL; -} - -/** - * Print a detailed representation of what a user has done with - * a given particular instance of this module, for user activity reports. - * - * @param object $course - * @param object $user - * @param object $mod - * @param object $chat - * @return bool - */ -function chat_user_complete($course, $user, $mod, $chat) { - return true; -} - /** * Given a course and a date, prints a summary of all chat rooms past and present * This function is called from block_recent_activity diff --git a/mod/folder/lang/en/folder.php b/mod/folder/lang/en/folder.php index 5a42a1507dd..f17e18ac262 100644 --- a/mod/folder/lang/en/folder.php +++ b/mod/folder/lang/en/folder.php @@ -39,7 +39,6 @@ A folder may be used * To provide a shared uploading space for teachers on the course page (keeping the folder hidden so that only teachers can see it)'; $string['modulename_link'] = 'mod/folder/view'; $string['modulenameplural'] = 'Folders'; -$string['neverseen'] = 'Never seen'; $string['page-mod-folder-x'] = 'Any folder module page'; $string['page-mod-folder-view'] = 'Folder module main page'; $string['pluginadministration'] = 'Folder administration'; diff --git a/mod/folder/lib.php b/mod/folder/lib.php index 3cf7675f03f..b2014f6b420 100644 --- a/mod/folder/lib.php +++ b/mod/folder/lib.php @@ -168,57 +168,6 @@ function folder_delete_instance($id) { return true; } -/** - * Return use outline - * @param object $course - * @param object $user - * @param object $mod - * @param object $folder - * @return object|null - */ -function folder_user_outline($course, $user, $mod, $folder) { - global $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'folder', - 'action'=>'view', 'info'=>$folder->id), 'time ASC')) { - - $numviews = count($logs); - $lastlog = array_pop($logs); - - $result = new stdClass(); - $result->info = get_string('numviews', '', $numviews); - $result->time = $lastlog->time; - - return $result; - } - return NULL; -} - -/** - * Return use complete - * @param object $course - * @param object $user - * @param object $mod - * @param object $folder - */ -function folder_user_complete($course, $user, $mod, $folder) { - global $CFG, $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'folder', - 'action'=>'view', 'info'=>$folder->id), 'time ASC')) { - $numviews = count($logs); - $lastlog = array_pop($logs); - - $strmostrecently = get_string('mostrecently'); - $strnumviews = get_string('numviews', '', $numviews); - - echo "$strnumviews - $strmostrecently ".userdate($lastlog->time); - - } else { - print_string('neverseen', 'folder'); - } -} - /** * Lists all browsable file areas * diff --git a/mod/imscp/lib.php b/mod/imscp/lib.php index d14013f2fb8..97c6d518d42 100644 --- a/mod/imscp/lib.php +++ b/mod/imscp/lib.php @@ -219,57 +219,6 @@ function imscp_delete_instance($id) { return true; } -/** - * Return use outline - * @param object $course - * @param object $user - * @param object $mod - * @param object $imscp - * @return object|null - */ -function imscp_user_outline($course, $user, $mod, $imscp) { - global $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'imscp', - 'action'=>'view', 'info'=>$imscp->id), 'time ASC')) { - - $numviews = count($logs); - $lastlog = array_pop($logs); - - $result = new stdClass(); - $result->info = get_string('numviews', '', $numviews); - $result->time = $lastlog->time; - - return $result; - } - return NULL; -} - -/** - * Return use complete - * @param object $course - * @param object $user - * @param object $mod - * @param object $imscp - */ -function imscp_user_complete($course, $user, $mod, $imscp) { - global $CFG, $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'imscp', - 'action'=>'view', 'info'=>$imscp->id), 'time ASC')) { - $numviews = count($logs); - $lastlog = array_pop($logs); - - $strmostrecently = get_string('mostrecently'); - $strnumviews = get_string('numviews', '', $numviews); - - echo "$strnumviews - $strmostrecently ".userdate($lastlog->time); - - } else { - print_string('neverseen', 'imscp'); - } -} - /** * Lists all browsable file areas * diff --git a/mod/page/lang/en/page.php b/mod/page/lang/en/page.php index e9928426b3f..44c72155df3 100644 --- a/mod/page/lang/en/page.php +++ b/mod/page/lang/en/page.php @@ -46,7 +46,6 @@ A page may be used * To embed several videos or sound files together with some explanatory text'; $string['modulename_link'] = 'mod/page/view'; $string['modulenameplural'] = 'Pages'; -$string['neverseen'] = 'Never seen'; $string['optionsheader'] = 'Display options'; $string['page-mod-page-x'] = 'Any page module page'; $string['page:addinstance'] = 'Add a new page resource'; diff --git a/mod/page/lib.php b/mod/page/lib.php index e775e5855b9..c36031aa248 100644 --- a/mod/page/lib.php +++ b/mod/page/lib.php @@ -191,57 +191,6 @@ function page_delete_instance($id) { return true; } -/** - * Return use outline - * @param object $course - * @param object $user - * @param object $mod - * @param object $page - * @return object|null - */ -function page_user_outline($course, $user, $mod, $page) { - global $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'page', - 'action'=>'view', 'info'=>$page->id), 'time ASC')) { - - $numviews = count($logs); - $lastlog = array_pop($logs); - - $result = new stdClass(); - $result->info = get_string('numviews', '', $numviews); - $result->time = $lastlog->time; - - return $result; - } - return NULL; -} - -/** - * Return use complete - * @param object $course - * @param object $user - * @param object $mod - * @param object $page - */ -function page_user_complete($course, $user, $mod, $page) { - global $CFG, $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'page', - 'action'=>'view', 'info'=>$page->id), 'time ASC')) { - $numviews = count($logs); - $lastlog = array_pop($logs); - - $strmostrecently = get_string('mostrecently'); - $strnumviews = get_string('numviews', '', $numviews); - - echo "$strnumviews - $strmostrecently ".userdate($lastlog->time); - - } else { - print_string('neverseen', 'page'); - } -} - /** * Given a course_module object, this function returns any * "extra" information that may be needed when printing diff --git a/mod/resource/lang/en/resource.php b/mod/resource/lang/en/resource.php index da2bce80bc7..ee8de871dcb 100644 --- a/mod/resource/lang/en/resource.php +++ b/mod/resource/lang/en/resource.php @@ -75,7 +75,6 @@ A file may be used * To provide draft files of certain software programs (eg Photoshop .psd) so students can edit and submit them for assessment'; $string['modulename_link'] = 'mod/resource/view'; $string['modulenameplural'] = 'Files'; -$string['neverseen'] = 'Never seen'; $string['notmigrated'] = 'This legacy resource type ({$a}) was not yet migrated, sorry.'; $string['optionsheader'] = 'Display options'; $string['page-mod-resource-x'] = 'Any file module page'; diff --git a/mod/resource/lib.php b/mod/resource/lib.php index 903e2278697..3fcb1bcd9b2 100644 --- a/mod/resource/lib.php +++ b/mod/resource/lib.php @@ -177,57 +177,6 @@ function resource_delete_instance($id) { return true; } -/** - * Return use outline - * @param object $course - * @param object $user - * @param object $mod - * @param object $resource - * @return object|null - */ -function resource_user_outline($course, $user, $mod, $resource) { - global $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'resource', - 'action'=>'view', 'info'=>$resource->id), 'time ASC')) { - - $numviews = count($logs); - $lastlog = array_pop($logs); - - $result = new stdClass(); - $result->info = get_string('numviews', '', $numviews); - $result->time = $lastlog->time; - - return $result; - } - return NULL; -} - -/** - * Return use complete - * @param object $course - * @param object $user - * @param object $mod - * @param object $resource - */ -function resource_user_complete($course, $user, $mod, $resource) { - global $CFG, $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'resource', - 'action'=>'view', 'info'=>$resource->id), 'time ASC')) { - $numviews = count($logs); - $lastlog = array_pop($logs); - - $strmostrecently = get_string('mostrecently'); - $strnumviews = get_string('numviews', '', $numviews); - - echo "$strnumviews - $strmostrecently ".userdate($lastlog->time); - - } else { - print_string('neverseen', 'resource'); - } -} - /** * Given a course_module object, this function returns any * "extra" information that may be needed when printing diff --git a/mod/upgrade.txt b/mod/upgrade.txt index 7c037a88779..f7611075ad0 100644 --- a/mod/upgrade.txt +++ b/mod/upgrade.txt @@ -8,6 +8,10 @@ information provided here is intended especially for developers. $plugin instead. The support for the legacy notation will be dropped in Moodle 2.10. * xxx_get_view_actions() and xxx_get_post_actions() will be ignored by new logging system for participation report. view_action and post_action will be detected by event's crud and edulevel. +* The functions xxx_user_outline() and xxx_user_complete() have been removed from the majority of core modules (see MDL-41286), + except for those that require unique functionality. These functions are used by the outline report, but now if they no longer + exist, the default behaviour is chosen, which supports the legacy and standard log storages introduced in 2.7 (see MDL-41266). + It is highly recommended you remove these functions from your module if they are simply performing the default behaviour. === 2.6 === diff --git a/mod/url/lang/en/url.php b/mod/url/lang/en/url.php index f59ba18bf11..d9a40260d6e 100644 --- a/mod/url/lang/en/url.php +++ b/mod/url/lang/en/url.php @@ -54,7 +54,6 @@ There are a number of display options for the URL, such as embedded or opening i Note that URLs can also be added to any other resource or activity type through the text editor.'; $string['modulename_link'] = 'mod/url/view'; $string['modulenameplural'] = 'URLs'; -$string['neverseen'] = 'Never seen'; $string['page-mod-url-x'] = 'Any URL module page'; $string['parameterinfo'] = '&parameter=variable'; $string['parametersheader'] = 'URL variables'; diff --git a/mod/url/lib.php b/mod/url/lib.php index b33b6e4fa3a..64d7ce0591f 100644 --- a/mod/url/lib.php +++ b/mod/url/lib.php @@ -193,57 +193,6 @@ function url_delete_instance($id) { return true; } -/** - * Return use outline - * @param object $course - * @param object $user - * @param object $mod - * @param object $url - * @return object|null - */ -function url_user_outline($course, $user, $mod, $url) { - global $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'url', - 'action'=>'view', 'info'=>$url->id), 'time ASC')) { - - $numviews = count($logs); - $lastlog = array_pop($logs); - - $result = new stdClass(); - $result->info = get_string('numviews', '', $numviews); - $result->time = $lastlog->time; - - return $result; - } - return NULL; -} - -/** - * Return use complete - * @param object $course - * @param object $user - * @param object $mod - * @param object $url - */ -function url_user_complete($course, $user, $mod, $url) { - global $CFG, $DB; - - if ($logs = $DB->get_records('log', array('userid'=>$user->id, 'module'=>'url', - 'action'=>'view', 'info'=>$url->id), 'time ASC')) { - $numviews = count($logs); - $lastlog = array_pop($logs); - - $strmostrecently = get_string('mostrecently'); - $strnumviews = get_string('numviews', '', $numviews); - - echo "$strnumviews - $strmostrecently ".userdate($lastlog->time); - - } else { - print_string('neverseen', 'url'); - } -} - /** * Given a course_module object, this function returns any * "extra" information that may be needed when printing diff --git a/mod/wiki/lib.php b/mod/wiki/lib.php index 2b21413f5d4..8db22c8f794 100644 --- a/mod/wiki/lib.php +++ b/mod/wiki/lib.php @@ -194,32 +194,6 @@ function wiki_reset_course_form_definition(&$mform) { $mform->addElement('advcheckbox', 'reset_wiki_comments', get_string('deleteallcomments')); } -/** - * Return a small object with summary information about what a - * user has done with a given particular instance of this module - * Used for user activity reports. - * $return->time = the time they did it - * $return->info = a short text description - * - * @return null - * @todo Finish documenting this function - **/ -function wiki_user_outline($course, $user, $mod, $wiki) { - $return = NULL; - return $return; -} - -/** - * Print a detailed representation of what a user has done with - * a given particular instance of this module, for user activity reports. - * - * @return boolean - * @todo Finish documenting this function - **/ -function wiki_user_complete($course, $user, $mod, $wiki) { - return true; -} - /** * Indicates API features that the wiki supports. * diff --git a/report/outline/index.php b/report/outline/index.php index 91c3b6a1a8e..f3733c784c1 100644 --- a/report/outline/index.php +++ b/report/outline/index.php @@ -60,11 +60,32 @@ $PAGE->set_heading($course->fullname); echo $OUTPUT->header(); echo $OUTPUT->heading(format_string($course->fullname)); -if (!$logstart = $DB->get_field_sql("SELECT MIN(time) FROM {log}")) { - print_error('logfilenotavailable'); +list($uselegacyreader, $useinternalreader, $minloginternalreader, $logtable) = report_outline_get_common_log_variables(); + +// If no legacy and no internal log then don't proceed. +if (!$uselegacyreader && !$useinternalreader) { + echo $OUTPUT->box_start('generalbox', 'notice'); + echo $OUTPUT->notification(get_string('nologreaderenabled', 'report_outline')); + echo $OUTPUT->box_end(); + echo $OUTPUT->footer(); + die(); } -echo $OUTPUT->container(get_string('computedfromlogs', 'admin', userdate($logstart)), 'loginfo'); +// We want to display the time we are beginning to get logs from in the heading. +// If we are using the legacy reader check the minimum time in that log table. +if ($uselegacyreader) { + $minlog = $DB->get_field_sql('SELECT min(time) FROM {log}'); +} + +// If we are using the internal reader check the minimum time in that table. +if ($useinternalreader) { + // If new log table has older data then don't use the minimum time obtained from the legacy table. + if (empty($minlog) || ($minloginternalreader <= $minlog)) { + $minlog = $minloginternalreader; + } +} + +echo $OUTPUT->container(get_string('computedfromlogs', 'admin', userdate($minlog)), 'loginfo'); $outlinetable = new html_table(); $outlinetable->attributes['class'] = 'generaltable boxaligncenter'; @@ -82,13 +103,65 @@ if ($showlastaccess) { $modinfo = get_fast_modinfo($course); -$sql = "SELECT cm.id, COUNT('x') AS numviews, MAX(time) AS lasttime - FROM {course_modules} cm - JOIN {modules} m ON m.id = cm.module - JOIN {log} l ON l.cmid = cm.id - WHERE cm.course = ? AND l.action LIKE 'view%' AND m.visible = 1 - GROUP BY cm.id"; -$views = $DB->get_records_sql($sql, array($course->id)); +// If using legacy log then get users from old table. +if ($uselegacyreader) { + // If we are going to use the internal (not legacy) log table, we should only get records + // from the legacy table that exist before we started adding logs to the new table. + $limittime = ''; + if (!empty($minloginternalreader)) { + $limittime = ' AND time < :timeto '; + $params['timeto'] = $minloginternalreader; + } + // Check if we need to show the last access. + $sqllasttime = ''; + if ($showlastaccess) { + $sqllasttime = ", MAX(time) AS lasttime"; + } + $logactionlike = $DB->sql_like('l.action', ':action'); + $sql = "SELECT cm.id, COUNT('x') AS numviews $sqllasttime + FROM {course_modules} cm + JOIN {modules} m + ON m.id = cm.module + JOIN {log} l + ON l.cmid = cm.id + WHERE cm.course = :courseid + AND $logactionlike + AND m.visible = :visible $limittime + GROUP BY cm.id"; + $params = array('courseid' => $course->id, 'action' => 'view%', 'visible' => 1); + $views = $DB->get_records_sql($sql, $params); +} + +// Get record from sql_internal_reader and merge with records obtained from legacy log (if needed). +if ($useinternalreader) { + // Check if we need to show the last access. + $sqllasttime = ''; + if ($showlastaccess) { + $sqllasttime = ", MAX(timecreated) AS lasttime"; + } + $sql = "SELECT contextinstanceid as cmid, COUNT('x') AS numviews $sqllasttime + FROM {" . $logtable . "} l + WHERE courseid = :courseid + AND anonymous = 0 + AND crud = 'r' + AND contextlevel = :contextmodule + GROUP BY contextinstanceid"; + $params = array('courseid' => $course->id, 'contextmodule' => CONTEXT_MODULE); + $v = $DB->get_records_sql($sql, $params); + + if (empty($views)) { + $views = $v; + } else { + // Merge two view arrays. + foreach ($v as $key => $value) { + if (isset($views[$key]) && !empty($views[$key]->numviews)) { + $views[$key]->numviews += $value->numviews; + } else { + $views[$key] = $value; + } + } + } +} $prevsecctionnum = 0; foreach ($modinfo->sections as $sectionnum=>$section) { diff --git a/report/outline/lang/en/report_outline.php b/report/outline/lang/en/report_outline.php index 7e6a0fc5b4f..828e2d9e537 100644 --- a/report/outline/lang/en/report_outline.php +++ b/report/outline/lang/en/report_outline.php @@ -25,6 +25,8 @@ $string['eventactivityreportviewed'] = 'Activity report viewed'; $string['eventoutlinereportviewed'] = 'Outline report viewed'; +$string['neverseen'] = 'Never seen'; +$string['nologreaderenabled'] = 'No log reader enabled'; $string['outline:view'] = 'View activity report'; $string['page-report-outline-x'] = 'Any outline report'; $string['page-report-outline-index'] = 'Course outline report'; diff --git a/report/outline/locallib.php b/report/outline/locallib.php index ba4761cc558..e301bec34ae 100644 --- a/report/outline/locallib.php +++ b/report/outline/locallib.php @@ -53,3 +53,209 @@ function report_outline_print_row($mod, $instance, $result) { } echo ""; } + +/** + * Returns an array of the commonly used log variables by the outline report. + * + * @return array the array of variables used + */ +function report_outline_get_common_log_variables() { + global $DB; + + static $uselegacyreader; + static $useinternalreader; + static $minloginternalreader; + static $logtable = null; + + if (isset($uselegacyreader) && isset($useinternalreader) && isset($minloginternalreader)) { + return array($uselegacyreader, $useinternalreader, $minloginternalreader, $logtable); + } + + $uselegacyreader = false; // Flag to determine if we should use the legacy reader. + $useinternalreader = false; // Flag to determine if we should use the internal reader. + $minloginternalreader = 0; // Set this to 0 for now. + + // Get list of readers. + $logmanager = get_log_manager(); + $readers = $logmanager->get_readers(); + + // Get preferred reader. + if (!empty($readers)) { + foreach ($readers as $readerpluginname => $reader) { + // If legacy reader is preferred reader. + if ($readerpluginname == 'logstore_legacy') { + $uselegacyreader = true; + break; + } + + // If sql_internal_reader is preferred reader. + if ($reader instanceof \core\log\sql_internal_reader) { + $useinternalreader = true; + $logtable = $reader->get_internal_log_table_name(); + $minloginternalreader = $DB->get_field_sql('SELECT min(timecreated) FROM {' . $logtable . '}'); + break; + } + } + } + + return array($uselegacyreader, $useinternalreader, $minloginternalreader, $logtable); +} + +/** + * Return the most commonly used user outline information. + * + * @param int $userid the id of the user + * @param int $cmid the course module id + * @param string $module the name of the module (eg. 'book') + * @param int $instanceid (eg. the 'id' in the 'book' table) + * @return stdClass|null if any information is found then a stdClass containing + * this info is returned, else null is. + */ +function report_outline_user_outline($userid, $cmid, $module, $instanceid) { + global $DB; + + list($uselegacyreader, $useinternalreader, $minloginternalreader, $logtable) = report_outline_get_common_log_variables(); + + // If using legacy log then get users from old table. + if ($uselegacyreader) { + // Create the params for the query. + $params = array('userid' => $userid, 'module' => $module, 'action' => 'view', 'info' => $instanceid); + // If we are going to use the internal (not legacy) log table, we should only get records + // from the legacy table that exist before we started adding logs to the new table. + $limittime = ''; + if (!empty($minloginternalreader)) { + $limittime = ' AND time < :timeto '; + $params['timeto'] = $minloginternalreader; + } + $select = "SELECT COUNT(id) "; + $from = "FROM {log} "; + $where = "WHERE userid = :userid + AND module = :module + AND action = :action + AND info = :info "; + if ($legacylogcount = $DB->count_records_sql($select . $from . $where . $limittime, $params)) { + $numviews = $legacylogcount; + + // Get the time for the last log. + $select = "SELECT MAX(time) "; + $lastlogtime = $DB->get_field_sql($select . $from . $where, $params); + + $result = new stdClass(); + $result->info = get_string('numviews', '', $numviews); + $result->time = $lastlogtime; + } + } + + // Get record from sql_internal_reader and combine with the number of views from the legacy log table (if needed). + if ($useinternalreader) { + $params = array('userid' => $userid, 'contextlevel' => CONTEXT_MODULE, 'contextinstanceid' => $cmid, 'crud' => 'r', + 'edulevel1' => core\event\base::LEVEL_PARTICIPATING, 'edulevel2' => core\event\base::LEVEL_TEACHING, + 'edulevel3' => core\event\base::LEVEL_OTHER, 'anonymous' => 0); + $select = "SELECT COUNT(*) as count "; + $from = "FROM {" . $logtable . "} "; + $where = "WHERE userid = :userid + AND contextlevel = :contextlevel + AND contextinstanceid = :contextinstanceid + AND crud = :crud + AND edulevel IN (:edulevel1, :edulevel2, :edulevel3) + AND anonymous = :anonymous"; + if ($internalreadercount = $DB->count_records_sql($select . $from . $where, $params)) { + if (!empty($numviews)) { + $numviews = $numviews + $internalreadercount; + } else { + $numviews = $internalreadercount; + } + + // Get the time for the last log. + $select = "SELECT MAX(timecreated) "; + $lastlogtime = $DB->get_field_sql($select . $from . $where, $params); + + $result = new stdClass(); + $result->info = get_string('numviews', '', $numviews); + $result->time = $lastlogtime; + } + } + + if (!empty($result)) { + return $result; + } + + return null; +} + +/** + * Display the most commonly used user complete information. + * + * @param int $userid the id of the user + * @param int $cmid the course module id + * @param string $module the name of the module (eg. 'book') + * @param int $instanceid (eg. the 'id' in the 'book' table) + * @return string + */ +function report_outline_user_complete($userid, $cmid, $module, $instanceid) { + global $DB; + + list($uselegacyreader, $useinternalreader, $minloginternalreader, $logtable) = report_outline_get_common_log_variables(); + + // If using legacy log then get users from old table. + if ($uselegacyreader) { + // Create the params for the query. + $params = array('userid' => $userid, 'module' => $module, 'action' => 'view', 'info' => $instanceid); + // If we are going to use the internal (not legacy) log table, we should only get records + // from the legacy table that exist before we started adding logs to the new table. + $limittime = ''; + if (!empty($minloginternalreader)) { + $limittime = ' AND time < :timeto '; + $params['timeto'] = $minloginternalreader; + } + $select = "SELECT COUNT(id) "; + $from = "FROM {log} "; + $where = "WHERE userid = :userid + AND module = :module + AND action = :action + AND info = :info "; + if ($legacylogcount = $DB->count_records_sql($select . $from . $where . $limittime, $params)) { + $numviews = $legacylogcount; + + // Get the time for the last log. + $select = "SELECT MAX(time) "; + $lastlogtime = $DB->get_field_sql($select . $from . $where, $params); + + $strnumviews = get_string('numviews', '', $numviews); + } + } + + // Get record from sql_internal_reader and combine with the number of views from the legacy log table (if needed). + if ($useinternalreader) { + $params = array('userid' => $userid, 'contextlevel' => CONTEXT_MODULE, 'contextinstanceid' => $cmid, 'crud' => 'r', + 'edulevel1' => core\event\base::LEVEL_PARTICIPATING, 'edulevel2' => core\event\base::LEVEL_TEACHING, + 'edulevel3' => core\event\base::LEVEL_OTHER, 'anonymous' => 0); + $select = "SELECT COUNT(*) as count "; + $from = "FROM {" . $logtable . "} "; + $where = "WHERE userid = :userid + AND contextlevel = :contextlevel + AND contextinstanceid = :contextinstanceid + AND crud = :crud + AND edulevel IN (:edulevel1, :edulevel2, :edulevel3) + AND anonymous = :anonymous"; + if ($internalreadercount = $DB->count_records_sql($select . $from . $where, $params)) { + if (!empty($numviews)) { + $numviews = $numviews + $internalreadercount; + } else { + $numviews = $internalreadercount; + } + + // Get the time for the last log. + $select = "SELECT MAX(timecreated) "; + $lastlogtime = $DB->get_field_sql($select . $from . $where, $params); + + $strnumviews = get_string('numviews', '', $numviews); + } + } + + if (!empty($strnumviews) && (!empty($lastlogtime))) { + return $strnumviews . ' - ' . get_string('mostrecently') . ' ' . userdate($lastlogtime); + } else { + return get_string('neverseen', 'report_outline'); + } +} diff --git a/report/outline/tests/behat/outline.feature b/report/outline/tests/behat/outline.feature new file mode 100644 index 00000000000..ffcea0f8cc3 --- /dev/null +++ b/report/outline/tests/behat/outline.feature @@ -0,0 +1,109 @@ +@report @report_outline +Feature: View an outline report + In order to ensure the outline report works as expected + As a teacher + I need to log in as a teacher and view the outline report + + Background: + Given the following "courses" exist: + | fullname | shortname | format | + | Course 1 | C1 | topics | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | Teacher | 1 | teacher1@asd.com + | student1 | Student | 1 | student1@asd.com | + | student2 | Student | 2 | student2@asd.com | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | C1 | student | + | student2 | C1 | student | + When I log in as "admin" + And I follow "Course 1" + And I turn editing mode on + And I add a "Forum" to section "1" and I fill the form with: + | Forum name | Forum name | + | Description | Forum description | + And I add a "Book" to section "1" and I fill the form with: + | Name | Book name | + | Description | Book description | + + @javascript + Scenario: View the outline report when only the legacy log reader is enabled + Given I navigate to "Manage log stores" node in "Site administration > Plugins > Logging" + And I click on "Enable" "link" in the "Legacy log" "table_row" + And I click on "Disable" "link" in the "Standard log" "table_row" + And I set the following administration settings values: + | Log legacy data | 1 | + And I log out + And I log in as "student1" + And I follow "Course 1" + And I follow "Forum name" + And I follow "Course 1" + And I follow "Book name" + And I log out + And I log in as "student2" + And I follow "Course 1" + And I follow "Book name" + And I log out + And I log in as "teacher1" + And I follow "Course 1" + When I navigate to "Activity report" node in "Course administration > Reports" + Then I should see "2" in the "//tr[contains(concat(' ', normalize-space(@class),' '),' r0 ')]/child::td[contains(concat(' ', normalize-space(@class),' '),' numviews ')]" "xpath_element" + And I should see "1" in the "//tr[contains(concat(' ', normalize-space(@class),' '),' r1 ')]/child::td[contains(concat(' ', normalize-space(@class),' '),' numviews ')]" "xpath_element" + + @javascript + Scenario: View the outline report when only the standard log reader is enabled + Given I navigate to "Manage log stores" node in "Site administration > Plugins > Logging" + And "Enable" "link" should exist in the "Legacy log" "table_row" + And "Disable" "link" should exist in the "Standard log" "table_row" + And I log out + And I log in as "student1" + And I follow "Course 1" + And I follow "Forum name" + And I follow "Course 1" + And I follow "Book name" + And I log out + And I log in as "student2" + And I follow "Course 1" + And I follow "Book name" + And I log out + And I log in as "admin" + And I follow "Course 1" + When I navigate to "Activity report" node in "Course administration > Reports" + Then I should see "2" in the "//tr[contains(concat(' ', normalize-space(@class),' '),' r0 ')]/child::td[contains(concat(' ', normalize-space(@class),' '),' numviews ')]" "xpath_element" + And I should see "1" in the "//tr[contains(concat(' ', normalize-space(@class),' '),' r1 ')]/child::td[contains(concat(' ', normalize-space(@class),' '),' numviews ')]" "xpath_element" + + @javascript + Scenario: View the outline report when both the standard and legacy log readers are enabled + Given I navigate to "Manage log stores" node in "Site administration > Plugins > Logging" + And I click on "Enable" "link" in the "Legacy log" "table_row" + And "Disable" "link" should exist in the "Standard log" "table_row" + And I set the following administration settings values: + | Log legacy data | 1 | + And I log out + And I log in as "student1" + And I follow "Course 1" + And I follow "Forum name" + And I follow "Course 1" + And I follow "Book name" + And I log out + And I log in as "student2" + And I follow "Course 1" + And I follow "Book name" + And I log out + And I log in as "teacher1" + And I follow "Course 1" + When I navigate to "Activity report" node in "Course administration > Reports" + Then I should see "2" in the "//tr[contains(concat(' ', normalize-space(@class),' '),' r0 ')]/child::td[contains(concat(' ', normalize-space(@class),' '),' numviews ')]" "xpath_element" + And I should see "1" in the "//tr[contains(concat(' ', normalize-space(@class),' '),' r1 ')]/child::td[contains(concat(' ', normalize-space(@class),' '),' numviews ')]" "xpath_element" + + @javascript + Scenario: View the outline report when no log reader is enabled + Given I navigate to "Manage log stores" node in "Site administration > Plugins > Logging" + And "Enable" "link" should exist in the "Legacy log" "table_row" + And I click on "Disable" "link" in the "Standard log" "table_row" + And I follow "Home" + And I follow "Course 1" + When I navigate to "Activity report" node in "Course administration > Reports" + Then I should see "No log reader enabled" diff --git a/report/outline/tests/behat/user.feature b/report/outline/tests/behat/user.feature new file mode 100644 index 00000000000..8a181dcdff9 --- /dev/null +++ b/report/outline/tests/behat/user.feature @@ -0,0 +1,107 @@ +@report @report_outline +Feature: View the user page for the outline report + In order to ensure the user page for the outline report works as expected + As a student + I need to log in as a student and view the user page for the outline report + + Background: + Given the following "courses" exist: + | fullname | shortname | format | showreports | + | Course 1 | C1 | topics | 1 | + And the following "users" exist: + | username | firstname | lastname | email | + | teacher1 | Teacher | 1 | teacher1@asd.com + | student1 | Student | 1 | student1@asd.com | + And the following "course enrolments" exist: + | user | course | role | + | teacher1 | C1 | editingteacher | + | student1 | C1 | student | + When I log in as "admin" + And I follow "Course 1" + And I turn editing mode on + And I add a "Folder" to section "1" and I fill the form with: + | Name | Folder name | + | Description | Folder description | + And I add a "URL" to section "1" and I fill the form with: + | Name | URL name | + | Description | URL description | + | External URL | http://www.google.com | + + @javascript + Scenario: View the user page when only the legacy log reader is enabled + Given I navigate to "Manage log stores" node in "Site administration > Plugins > Logging" + And I click on "Enable" "link" in the "Legacy log" "table_row" + And I click on "Disable" "link" in the "Standard log" "table_row" + And I set the following administration settings values: + | Log legacy data | 1 | + And I log out + And I log in as "student1" + And I follow "Course 1" + # We want to view this multiple times, to make sure the count is working. + And I follow "Folder name" + And I follow "Folder name" + And I follow "Folder name" + And I follow "Folder name" + And I follow "Course 1" + # We want to view this multiple times, to make sure the count is working. + And I follow "URL name" + And I follow "URL name" + And I follow "URL name" + When I navigate to "Outline report" node in "My profile settings > Activity reports" + Then I should see "4 views" in the "Folder name" "table_row" + And I should see "3 views" in the "URL name" "table_row" + And I navigate to "Complete report" node in "My profile settings > Activity reports" + And I should see "4 views" + And I should see "3 views" + + @javascript + Scenario: View the user page when only the standard log reader is enabled + Given I navigate to "Manage log stores" node in "Site administration > Plugins > Logging" + And "Enable" "link" should exist in the "Legacy log" "table_row" + And "Disable" "link" should exist in the "Standard log" "table_row" + And I log out + And I log in as "student1" + And I follow "Course 1" + # We want to view this multiple times, to make sure the count is working. + And I follow "Folder name" + And I follow "Folder name" + And I follow "Folder name" + And I follow "Folder name" + And I follow "Course 1" + # We want to view this multiple times, to make sure the count is working. + And I follow "URL name" + And I follow "URL name" + And I follow "URL name" + When I navigate to "Outline report" node in "My profile settings > Activity reports" + Then I should see "4 views" in the "Folder name" "table_row" + And I should see "3 views" in the "URL name" "table_row" + And I navigate to "Complete report" node in "My profile settings > Activity reports" + And I should see "4 views" + And I should see "3 views" + + @javascript + Scenario: View the user page when both the standard and legacy log readers are enabled + Given I navigate to "Manage log stores" node in "Site administration > Plugins > Logging" + And I click on "Enable" "link" in the "Legacy log" "table_row" + And "Disable" "link" should exist in the "Standard log" "table_row" + And I set the following administration settings values: + | Log legacy data | 1 | + And I log out + And I log in as "student1" + And I follow "Course 1" + # We want to view this multiple times, to make sure the count is working. + And I follow "Folder name" + And I follow "Folder name" + And I follow "Folder name" + And I follow "Folder name" + And I follow "Course 1" + # We want to view this multiple times, to make sure the count is working. + And I follow "URL name" + And I follow "URL name" + And I follow "URL name" + When I navigate to "Outline report" node in "My profile settings > Activity reports" + Then I should see "4 views" in the "Folder name" "table_row" + And I should see "3 views" in the "URL name" "table_row" + And I navigate to "Complete report" node in "My profile settings > Activity reports" + And I should see "4 views" + And I should see "3 views" diff --git a/report/outline/user.php b/report/outline/user.php index a4cbd509603..03dd659d613 100644 --- a/report/outline/user.php +++ b/report/outline/user.php @@ -25,6 +25,7 @@ require('../../config.php'); require_once($CFG->dirroot.'/report/outline/locallib.php'); +require_once($CFG->dirroot.'/report/outline/lib.php'); $userid = required_param('id', PARAM_INT); $courseid = required_param('course', PARAM_INT); @@ -109,29 +110,33 @@ foreach ($sections as $i => $section) { $user_outline = $mod->modname."_user_outline"; if (function_exists($user_outline)) { $output = $user_outline($course, $user, $mod, $instance); - report_outline_print_row($mod, $instance, $output); + } else { + $output = report_outline_user_outline($user->id, $cmid, $mod->modname, $instance->id); } + report_outline_print_row($mod, $instance, $output); break; case "complete": $user_complete = $mod->modname."_user_complete"; + $image = $OUTPUT->pix_icon('icon', $mod->modfullname, 'mod_'.$mod->modname, array('class'=>'icon')); + echo "

$image $mod->modfullname: ". + "wwwroot/mod/$mod->modname/view.php?id=$mod->id\">". + format_string($instance->name,true)."

"; + + ob_start(); + + echo ""; - $output = ob_get_contents(); - ob_end_clean(); + $output = ob_get_contents(); + ob_end_clean(); - if (str_replace(' ', '', $output) != '') { - echo $output; - } + if (str_replace(' ', '', $output) != '') { + echo $output; } break; }