Commit ee54e805 authored by Son Nguyen's avatar Son Nguyen Committed by Gerrit Code Review
Browse files

Merge "Bug 1483963 - Better reporting on login activity"

parents 0ef385ef 19af23b2
......@@ -21,7 +21,7 @@ $offset = param_integer('offset', 0);
$extradata = json_decode(param_variable('extradata'));
$type = param_alpha('type', 'users');
$subpages = array('users', 'groups', 'views', 'content', 'historical', 'institutions');
$subpages = array('users', 'groups', 'views', 'content', 'historical', 'institutions', 'logins');
if (!in_array($type, $subpages)) {
$type = 'users';
}
......@@ -30,12 +30,18 @@ if ($type == 'historical') {
$field = (isset($extradata->field) ? $extradata->field : 'count_usr');
}
if ($type == 'institutions') {
if ($type == 'institutions' || $type == 'logins') {
$sort = (isset($extradata->sort) ? $extradata->sort : 'displayname');
$sortdesc = (isset($extradata->sortdesc) ? $extradata->sortdesc : false);
$start = param_alphanumext('start', null);
$end = param_alphanumext('end', null);
}
switch ($type) {
case 'logins':
$data = institution_logins_statistics($limit, $offset, $sort, $sortdesc, $start, $end);
$data = $data['table'];
break;
case 'institutions':
$data = institution_comparison_stats_table($limit, $offset, $sort, $sortdesc);
break;
......
......@@ -19,7 +19,7 @@ require(get_config('libroot') . 'registration.php');
define('TITLE', get_string('sitestatistics', 'admin'));
$type = param_alpha('type', 'users');
$subpages = array('users', 'groups', 'views', 'content', 'historical', 'institutions');
$subpages = array('users', 'groups', 'views', 'content', 'historical', 'institutions', 'logins');
$offset = param_integer('offset', 0);
$limit = param_integer('limit', 10);
......@@ -31,14 +31,19 @@ if ($type == 'historical') {
$field = param_alphanumext('field', 'count_usr');
}
if ($type == 'institutions') {
if ($type == 'institutions' || $type == 'logins') {
$sort = param_alphanumext('sort', 'displayname');
$sortdesc = param_boolean('sortdesc');
$start = param_alphanumext('start', null);
$end = param_alphanumext('end', null);
}
$sitedata = site_statistics(true);
switch ($type) {
case 'logins':
$data = institution_logins_statistics($limit, $offset, $sort, $sortdesc, $start, $end);
break;
case 'institutions':
$data = institution_comparison_statistics($limit, $offset, $sort, $sortdesc);
break;
......
......@@ -1650,11 +1650,12 @@ class LiveUser extends User {
$this->populate($user);
session_regenerate_id(true);
$time = time();
$this->lastlastlogin = $this->lastlogin;
$this->lastlogin = time();
$this->lastaccess = time();
$this->lastlogin = $time;
$this->lastaccess = $time;
$this->sessionid = session_id();
$this->logout_time = time() + get_config('session_timeout');
$this->logout_time = $time + get_config('session_timeout');
$this->sesskey = get_random_key();
// We need a user->id before we load_c*_preferences
......@@ -1662,6 +1663,9 @@ class LiveUser extends User {
$this->activityprefs = load_activity_preferences($user->id);
$this->accountprefs = load_account_preferences($user->id);
// Record the successful login in the usr_login_data table
insert_record('usr_login_data', (object) array('usr' => $user->id, 'ctime' => db_format_timestamp($time)));
// If user has chosen a language while logged out, save it as their lang pref.
$sessionlang = $this->SESSION->get('lang');
if (!empty($sessionlang) && $sessionlang != 'default'
......
......@@ -293,6 +293,8 @@ $string['viewsbytype'] = 'Pages by type';
$string['userstatstabletitle'] = 'Daily user statistics';
$string['groupstatstabletitle'] = 'Biggest groups';
$string['viewstatstabletitle'] = 'Most popular pages';
$string['institutionloginstabletitle'] = 'Active institutions';
$string['institutionloginstablesubtitle'] = 'For %s - %s';
$string['visitedtimesrank'] = 'visited %s times, ranked number %s';
$string['pageownedby'] = 'Owned by';
$string['contentstats'] = 'modified %s times for the current week and %s times in total';
......
......@@ -1163,6 +1163,7 @@ $string['content'] = 'Content';
$string['modified'] = 'Modified';
$string['historical'] = 'Historical data';
$string['institutions'] = 'Institutions';
$string['logins'] = 'Logins';
$string['members'] = 'Members';
$string['blocks'] = 'Blocks';
$string['artefacts'] = 'Artefacts';
......
......@@ -196,4 +196,7 @@ $string['user-count'] = 'User';
$string['institutiondataweekly'] = 'Institution weekly data';
$string['usersbytype'] = 'Users by type';
$string['staff'] = 'Staff';
$string['admins'] = 'Administrators';
\ No newline at end of file
$string['admins'] = 'Administrators';
$string['activeusers'] = "Active users";
$string['logins'] = "Logins";
\ No newline at end of file
......@@ -210,6 +210,17 @@
<KEY NAME="institution" TYPE="foreign" FIELDS="institution" REFTABLE="institution" REFFIELDS="name"/>
</KEYS>
</TABLE>
<TABLE NAME="usr_login_data">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" />
<FIELD NAME="usr" TYPE="int" LENGTH="10" NOTNULL="true"/>
<FIELD NAME="ctime" TYPE="datetime" NOTNULL="true"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
<KEY NAME="usr" TYPE="foreign" FIELDS="usr" REFTABLE="usr" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="usr_session">
<FIELDS>
<FIELD NAME="usr" TYPE="int" LENGTH="10" NOTNULL="true" />
......
......@@ -4156,5 +4156,30 @@ function xmldb_core_upgrade($oldversion=0) {
}
}
if ($oldversion < 2015081000) {
log_debug('Add user_login_data table to record when a user logs in');
$table = new XMLDBTable('usr_login_data');
$table->addFieldInfo('id', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
$table->addFieldInfo('usr', XMLDB_TYPE_INTEGER, 10, false, XMLDB_NOTNULL);
$table->addFieldInfo('ctime', XMLDB_TYPE_DATETIME, null, null, XMLDB_NOTNULL);
$table->addKeyInfo('primary', XMLDB_KEY_PRIMARY, array('id'));
$table->addKeyInfo('usrloginfk', XMLDB_KEY_FOREIGN, array('usr'), 'usr', array('id'));
create_table($table);
// Insert info about current users's logins
$results = get_records_sql_array("SELECT id,lastlogin FROM usr WHERE deleted = 0 AND lastlogin IS NOT NULL");
$count = 0;
$limit = 1000;
$total = count($results);
foreach ($results as $result) {
insert_record('usr_login_data', (object) array('usr' => $result->id, 'ctime' => $result->lastlogin));
$count++;
if (($count % $limit) == 0 || $count == $total) {
log_debug("$count/$total");
set_time_limit(30);
}
}
}
return $status;
}
......@@ -2111,3 +2111,136 @@ function graph_institution_data_weekly($type = null, $institutiondata) {
function graph_institution_data_daily(&$institutiondata) {
institution_view_type_graph(null, $institutiondata);
}
/**
* Create logins by institution layout for the site statistics page
*
* @param int $limit Limit results
* @param int $offset Starting offset
* @param string $sort DB Column to sort by
* @param string/int $sortdesc The direction to sort the $sort column by
* @param string $start The start date to filter results by - format 'YYYY-MM-DD HH:MM:SS'
* @param string $end The end date to filter results by - format 'YYYY-MM-DD HH:MM:SS'
*
* @results array Results containing the html / pagination data
*/
function institution_logins_statistics($limit, $offset, $sort, $sortdesc, $start=null, $end=null) {
// If no start/end dates provided then default to the previous full month
$start = ($start) ? $start : date('Y-m-d H:i:s', mktime(0,0,0,date('n')-1,1,date('Y'))); // first day of previous month
$end = ($end) ? $end : date('Y-m-d H:i:s', mktime(23,59,59,date('n'),0,date('Y'))); // last day of previous month
$data = array();
$data['tableheadings'] = array(
array(
'name' => get_string('institution'),
'class' => 'search-results-sort-column' . ($sort == 'displayname' ? ' ' . ($sortdesc ? 'desc' : 'asc') : ''),
'link' => get_config('wwwroot') . 'admin/statistics.php?type=logins&sort=displayname&sortdesc=' . ($sort == 'displayname' ? !$sortdesc : false) . '&limit=' . $limit . '&offset=' . $offset . '&start=' . $start . '&end=' . $end
),
array(
'name' => get_string('logins', 'statistics'),
'class' => 'search-results-sort-column' . ($sort == 'count_logins' ? ' ' . ($sortdesc ? 'desc' : 'asc') : ''),
'link' => get_config('wwwroot') . 'admin/statistics.php?type=logins&sort=count_logins&sortdesc=' . ($sort == 'count_logins' ? !$sortdesc : true) . '&limit=' . $limit . '&offset=' . $offset . '&start=' . $start . '&end=' . $end
),
array(
'name' => get_string('activeusers', 'statistics'),
'class' => 'search-results-sort-column' . ($sort == 'count_active' ? ' ' . ($sortdesc ? 'desc' : 'asc') : ''),
'link' => get_config('wwwroot') . 'admin/statistics.php?type=logins&sort=count_active&sortdesc=' . ($sort == 'count_active' ? !$sortdesc : true) . '&limit=' . $limit . '&offset=' . $offset . '&start=' . $start . '&end=' . $end
),
);
$data['table'] = institution_logins_stats_table($limit, $offset, $sort, $sortdesc, $start, $end);
$data['tabletitle'] = get_string('institutionloginstabletitle', 'admin');
$data['tablesubtitle'] = get_string('institutionloginstablesubtitle', 'admin', format_date(strtotime($start), 'strftimedate'), format_date(strtotime($end), 'strftimedate'));
$data['summary'] = $data['table']['count'] == 0 ? get_string('nostats', 'admin') : null;
return $data;
}
/**
* Create logins by institution table for the site statistics page
*
* @param int $limit Limit results
* @param int $offset Starting offset
* @param string $sort DB Column to sort by
* @param string/int $sortdesc The direction to sort the $sort column by
* @param string $start The start date to filter results by - format 'YYYY-MM-DD HH:MM:SS'
* @param string $end The end date to filter results by - format 'YYYY-MM-DD HH:MM:SS'
*
* @results array Results containing the html / pagination data
*/
function institution_logins_stats_table($limit, $offset, $sort, $sortdesc, $start, $end) {
global $USER;
$rawdata = users_active_data(null, null, $sort, $sortdesc, $start, $end);
$count = ($rawdata) ? count($rawdata) : 0;
$pagination = build_pagination(array(
'id' => 'stats_pagination',
'url' => get_config('wwwroot') . 'admin/statistics.php?type=logins&start=' . date('Y-m-d', strtotime($start)) . '&end=' . date('Y-m-d', strtotime($end)),
'jsonscript' => 'admin/statistics.json.php',
'datatable' => 'statistics_table',
'count' => $count,
'limit' => $limit,
'offset' => $offset,
'setlimit' => true,
));
$result = array(
'count' => $count,
'tablerows' => '',
'pagination' => $pagination['html'],
'pagination_js' => $pagination['javascript'],
);
if ($count < 1) {
return $result;
}
$csvfields = array('name', 'displayname', 'count_logins', 'count_active');
$USER->set_download_file(generate_csv($rawdata, $csvfields), 'userloginstatistics.csv', 'text/csv');
$result['csv'] = true;
$data = array_slice($rawdata, $offset, $limit);
$smarty = smarty_core();
$smarty->assign('data', $data);
$result['tablerows'] = $smarty->fetch('admin/userloginsummary.tpl');
return $result;
}
/**
* Get records of how many users have their last login fall within a certain time period.
* Group the results by institution.
*
* @param string $start The start of the time period - format 'YYYY-MM-DD HH:II:SS'
* @param string $end The end of the time period - format 'YYYY-MM-DD HH:II:SS'
* @param string $institution Restrict the results to a particular institution.
*
* @result int $count The total count of 'users per institution' rows
* @result array $results The count of users per institution
*/
function users_active_data($limit=0, $offset=0, $sort='displayname', $sortdesc='DESC', $start = null, $end = null, $institution = null) {
if (!$start) {
$start = db_format_timestamp(strtotime("-1 months"));
}
if (!$end) {
$end = db_format_timestamp(time());
}
$sql = "SELECT CASE WHEN i.name IS NOT NULL THEN i.name ELSE 'mahara' END AS name,
CASE WHEN i.displayname IS NOT NULL THEN i.displayname ELSE 'No institution' END AS displayname,
COUNT(u.ctime) AS count_logins, COUNT(DISTINCT u.usr) AS count_active
FROM {usr_login_data} u
LEFT JOIN {usr_institution} ui ON ui.usr = u.usr
LEFT JOIN {institution} i ON i.name = ui.institution
WHERE (u.ctime >= ? AND u.ctime <= ?)";
$where = array($start, $end);
if ($institution) {
$sql .= " AND i.name = ?";
$where[] = $institution;
}
$sql .= " GROUP BY i.name, i.displayname ORDER BY " . $sort . " " . ($sortdesc ? 'DESC' : 'ASC');
$results = get_records_sql_array($sql, $where, $offset, $limit);
return $results;
}
......@@ -1520,6 +1520,7 @@ function delete_user($userid) {
delete_records('usr_password_request', 'usr', $userid);
delete_records('usr_watchlist_view', 'usr', $userid);
delete_records('view_access', 'usr', $userid);
delete_records('usr_login_data', 'usr', $userid);
// Remove the user's views & artefacts
$viewids = get_column('view', 'id', 'owner', $userid);
......
......@@ -16,7 +16,7 @@ $config = new stdClass();
// See https://wiki.mahara.org/index.php/Developer_Area/Version_Numbering_Policy
// For upgrades on stable branches, increment the version by one. On master, use the date.
$config->version = 2015072000;
$config->version = 2015081000;
$config->series = '15.10';
$config->release = '15.10dev';
$config->minupgradefrom = 2009022600;
......
......@@ -20,9 +20,10 @@
</div>
<div class="subpage panel-body row" id="site-stats-wrap2">
<div id="statistics_table_container" class="col-md-12">
<h3>{$subpagedata.tabletitle}</h3>
{if $subpagedata.tablesubtitle}<div class="small">{$subpagedata.tablesubtitle}</div>{/if}
{if $subpagedata.table.count == 0}{else}
<div id="statistics_table_container" class="col-md-12">
<h3>{$subpagedata.tabletitle}</h3>
<table id="statistics_table" class="table table-striped fullwidth">
<thead>
<tr>
......@@ -36,8 +37,8 @@
</tbody>
</table>
{$subpagedata.table.pagination|safe}
</div>
{/if}
</div>
{if $subpagedata.summary}
<div class="col-md-12 image-right">
{$subpagedata.summary|safe}
......
{if $data}
{foreach from=$data item=institution}
<tr>
<td><a href="{$WWWROOT}institution/index.php?institution={$institution->name}">{$institution->displayname}</a></td>
<td>{$institution->count_logins}</td>
<td>{$institution->count_active}</td>
</tr>
{/foreach}
{/if}
......@@ -57,6 +57,7 @@ Scenario: Clicking randomly around Mahara (Bug: 1426983)
# Checking Admin home Menu and submenu
And I choose "Register" in "Admin home"
And I choose "Site statistics" in "Admin home"
And I follow "Logins"
And I choose "Overview" in "Admin home"
# Checking Configure site Menu and submenu
And I choose "Site options" in "Configure site"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment