diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index e107a5039..acf7de02e 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -55,6 +55,7 @@ - rfe: After committing a version there is now a back to site link - rfe: Added sort order to Folder assets - rfe: Added canEdit and canAddFile template vars to Folder assets + - rfe: Add logged-in time to Login History 7.5.22 - fixed: Layout template now gets prepared correctly diff --git a/docs/upgrades/upgrade_7.5.21-7.6.0.pl b/docs/upgrades/upgrade_7.5.21-7.6.0.pl index 6674a4c7c..91e876cbe 100644 --- a/docs/upgrades/upgrade_7.5.21-7.6.0.pl +++ b/docs/upgrades/upgrade_7.5.21-7.6.0.pl @@ -32,6 +32,7 @@ addUrlToAssetHistory ( $session ); ##This sub MUST GO FIRST removeDoNothingOnDelete( $session ); fixIsPublicOnTemplates ( $session ); addSortOrderToFolder( $session ); +addLoginTimeStats( $session ); addEMSBadgeTemplate ( $session ); redirectChoice ($session); @@ -68,6 +69,15 @@ sub addSortOrderToFolder { print "Done.\n" unless $quiet; } +#---------------------------------------------------------------------------- +sub addLoginTimeStats { + my $session = shift; + print "\tAdding login time statistics... " unless $quiet; + $session->db->write( "alter table userLoginLog add column sessionId varchar(22)" ); + $session->db->write( "alter table userLoginLog add column lastPageViewed int(11)" ); + print "Done.\n" unless $quiet; +} + #---------------------------------------------------------------------------- sub removeDoNothingOnDelete { my $session = shift; diff --git a/lib/WebGUI/Auth.pm b/lib/WebGUI/Auth.pm index d3bfc430d..9dd26c7b2 100644 --- a/lib/WebGUI/Auth.pm +++ b/lib/WebGUI/Auth.pm @@ -102,13 +102,18 @@ sub _isValidUsername { #------------------------------------------------------------------- sub _logLogin { my $self = shift; - $self->session->db->write("insert into userLoginLog values (?,?,?,?,?)", - [ $_[0], - $_[1], - $self->session->datetime->time(), - $self->session->env->getIp, - $self->session->env->get("HTTP_USER_AGENT") ] - ); + $self->timeRecordSession; + $self->session->db->write("insert into userLoginLog values (?,?,?,?,?,?,?)", + [ + $_[0], + $_[1], + $self->session->datetime->time(), + $self->session->env->getIp, + $self->session->env->get("HTTP_USER_AGENT"), + $self->session->getId, + $self->session->datetime->time(), + ] + ); } @@ -911,6 +916,32 @@ sub showMessageOnLogin { return $output; } +#---------------------------------------------------------------------------- + +=head2 timeRecordSession + +Record the last page viewed and the time viewed for the user + +=cut + +sub timeRecordSession { + my $self = shift; + my ($nonTimeRecordedRows) = $self->session->db->quickArray("select count(*) from userLoginLog where lastPageViewed = timeStamp and sessionId = ? ", [$self->session->getId] ); + if ($nonTimeRecordedRows eq "1") { + # We would normally expect to only find one entry + $self->session->db->write("update userLoginLog set lastPageViewed = (select lastPageView from userSession where sessionId = ?) where lastPageViewed = timeStamp and sessionId = ? ", + [ $self->session->getId, + $self->session->getId]); + } elsif ($nonTimeRecordedRows eq "0") { + # Do nothing + } else { + # If something strange happened and we ended up with > 1 matching rows, cut our losses and remove offending userLoginLog rows (otherwise we + # could end up with ridiculously long user recorded times) + $self->session->errorHandler->warn("More than 1 old userLoginLog rows found, removing offending rows"); + $self->session->db->write("delete from userLoginLog where lastPageViewed = timeStamp and sessionId = ? ", [$self->session->getId] ); + } +} + #------------------------------------------------------------------- =head2 user ( [user] ) diff --git a/lib/WebGUI/Operation/LoginHistory.pm b/lib/WebGUI/Operation/LoginHistory.pm index c940ee112..dce1bb102 100644 --- a/lib/WebGUI/Operation/LoginHistory.pm +++ b/lib/WebGUI/Operation/LoginHistory.pm @@ -61,7 +61,21 @@ sub www_viewLoginHistory { $row[$i] .= ''.$data{status}.''; $row[$i] .= ''.$session->datetime->epochToHuman($data{timeStamp},"%H:%n%p %M/%D/%y").''; $row[$i] .= ''.$data{ipAddress}.''; - $row[$i] .= ''.$data{userAgent}.''; + $row[$i] .= ''.$data{userAgent}.''; + $row[$i] .= ''.$data{sessionId}.''; + if ($data{lastPageViewed}) { + if ($data{lastPageViewed} == $data{timeStamp}) { + $row[$i] .= "Active"; + $row[$i] .= "Active"; + } else { + $row[$i] .= ''.$session->datetime->epochToHuman($data{lastPageViewed},"%H:%n%p %M/%D/%y").''; + my ($interval, $units) = $session->datetime->secondsToInterval($data{lastPageViewed} - $data{timeStamp}); + $row[$i] .= "$interval $units"; + } + } else { + $row[$i] .= ""; + $row[$i] .= ""; + } $i++; } $sth->finish; @@ -72,7 +86,10 @@ sub www_viewLoginHistory { $output .= ''.$i18n->get(434).''; $output .= ''.$i18n->get(429).''; $output .= ''.$i18n->get(431).''; - $output .= ''.$i18n->get(433).''; + $output .= ''.$i18n->get(433).''; + $output .= '' . $i18n->get( 435 ) . ''; + $output .= '' . $i18n->get( 430 ) . ''; + $output .= '' . $i18n->get( "session length" ) . ''; $output .= $p->getPage($session->form->process("pn")); $output .= ''; $output .= $p->getBar($session->form->process("pn")); diff --git a/lib/WebGUI/Operation/User.pm b/lib/WebGUI/Operation/User.pm index dba5a4d5e..8775d2e6c 100644 --- a/lib/WebGUI/Operation/User.pm +++ b/lib/WebGUI/Operation/User.pm @@ -663,33 +663,54 @@ sub www_listUsers { '.$i18n->get(454).' '.$i18n->get(429).' '.$i18n->get(434).' + '.$i18n->get(430).' + '.$i18n->get( "time recorded" ).' '; my $p = doUserSearch($session,"listUsers",1); foreach my $data (@{$p->getPageData}) { - $output .= ''; - $output .= ''.$status{$data->{status}}.''; - $output .= ''.$data->{username}.''; - $output .= ''.$data->{email}.''; - $output .= ''.$session->datetime->epochToHuman($data->{dateCreated},"%z").''; - $output .= ''.$session->datetime->epochToHuman($data->{lastUpdated},"%z").''; - my ($lastLoginStatus, $lastLogin) = $session->db->quickArray("select status,timeStamp from userLoginLog where - userId=".$session->db->quote($data->{userId})." order by timeStamp DESC"); - if ($lastLogin) { - $output .= ''.$session->datetime->epochToHuman($lastLogin).''; - } else { - $output .= ' - '; - } - if ($lastLoginStatus) { - $output .= ''.$lastLoginStatus.''; - } else { - $output .= ' - '; - } - $output .= ''; + $output .= ''; + $output .= ''.$status{$data->{status}}.''; + $output .= ''.$data->{username}.''; + $output .= ''.$data->{email}.''; + $output .= ''.$session->datetime->epochToHuman($data->{dateCreated},"%z").''; + $output .= ''.$session->datetime->epochToHuman($data->{lastUpdated},"%z").''; + # Total Time Recorded is computed from userLoginLog table + my ($totalTimeRecorded)= $session->db->quickArray("select sum(lastPageViewed-timeStamp) from userLoginLog where userId = ?", [$data->{userId}]); + my ($lastLoginStatus, $lastLogin, $lastPageView) + = $session->db->quickArray( + "select ull.status, ull.timeStamp, us.lastPageView + from userLoginLog ull, userSession us + where ull.sessionId = us.sessionId and ull.lastPageViewed != ull.timeStamp and + ull.userId=".$session->db->quote($data->{userId})." + order by ull.timeStamp DESC" + ); + if ($lastLogin) { + $output .= ''.$session->datetime->epochToHuman($lastLogin).''; + } + else { + $output .= ' - '; + } + if ($lastLoginStatus) { + $output .= ''.$lastLoginStatus.''; + } + else { + $output .= ' - '; + } + if ($lastPageView) { + $output .= ' '.$session->datetime->epochToHuman($lastPageView).''; + my ($interval, $units) = $session->datetime->secondsToInterval($totalTimeRecorded); + $output .= "$interval $units"; + } + else { + $output .= " - "; + $output .= " - "; + } + $output .= ''; } - $output .= ''; - $p->setAlphabeticalKey('username'); - $output .= $p->getBarTraditional; + $output .= ''; + $p->setAlphabeticalKey('username'); + $output .= $p->getBarTraditional; my $submenu = _submenu( $session, { workarea => $output, } diff --git a/lib/WebGUI/Workflow/Activity/DeleteExpiredSessions.pm b/lib/WebGUI/Workflow/Activity/DeleteExpiredSessions.pm index 5277f5014..b6dd12d13 100644 --- a/lib/WebGUI/Workflow/Activity/DeleteExpiredSessions.pm +++ b/lib/WebGUI/Workflow/Activity/DeleteExpiredSessions.pm @@ -68,21 +68,37 @@ See WebGUI::Workflow::Activity::execute() for details. sub execute { my $self = shift; - my $sth = $self->session->db->read("select sessionId from userSession where expiressession->db->read("select sessionId, lastPageView from userSession where expiresgetTTL; - while (my ($sessionId) = $sth->array) { + + while ( my ( $sessionId, $lastPageView ) = $sth->array ) { + # timeRecordSessions + my ($nonTimeRecordedRows) = $self->session->db->quickArray("select count(*) from userLoginLog where lastPageViewed = timeStamp and sessionId = ? ", [$sessionId] ); + if ($nonTimeRecordedRows eq "1") { + # We would normally expect to only find one entry + $self->session->db->write("update userLoginLog set lastPageViewed = ? where lastPageViewed = timeStamp and sessionId = ? ", + [ $lastPageView, $sessionId ]); + } elsif ($nonTimeRecordedRows eq "0") { + # Do nothing + } else { + # If something strange happened and we ended up with > 1 matching rows, cut our losses and remove offending userLoginLog rows (otherwise we + # could end up with ridiculously long user recorded times) + $self->session->errorHandler->warn("More than 1 old userLoginLog rows found, removing offending rows"); + $self->session->db->write("delete from userLoginLog where lastPageViewed = timeStamp and sessionId = ? ", [$sessionId] ); + } my $session = WebGUI::Session->open($self->session->config->getWebguiRoot, $self->session->config->getFilename, undef, undef, $sessionId, 1); if (defined $session) { $session->var->end; $session->close; } if ((time() - $time) > $ttl) { - $sth->finish; + $sth->finish; return $self->WAITING; } - } - return $self->COMPLETE; + } + + return $self->COMPLETE; } diff --git a/lib/WebGUI/i18n/English/WebGUI.pm b/lib/WebGUI/i18n/English/WebGUI.pm index ee1288776..080cbfcdf 100644 --- a/lib/WebGUI/i18n/English/WebGUI.pm +++ b/lib/WebGUI/i18n/English/WebGUI.pm @@ -4129,6 +4129,18 @@ LongTruncOk=1

context => q{Title of the template created by the Site Setup screen}, }, + 'session length' => { + message => q{Session Length}, + lastUpdated => 0, + context => q{The length the session has been alive}, + }, + + "time recorded" => { + message => q{Time Recorded (excludes active sessions)}, + lastUpdated => 0, + context => q{Column heading for the total logged in time for the user}, + }, + }; 1;