WebGUI
      Click here to register.
      
irc://irc.freenode.net#webgui

iPhoneGuy: WebGUI is a pile of crap.
rizen: If WebGUI is such a pile of crap, why do you use it?
iPhoneGuy: Because it's the best pile of crap out there.

If this is what people who hate us are saying, imagine what people who love us will say. Come join us on IRC.


     Request Features > Request For Enhancement

Logged-in Time

User patspam
Date 1/3/2007 2:08 am
Version WebGUI
Views 1977
Rating 7    Rate [
|
]
Difficulty 1
Karma So Far 508
Karma Rank 508.000000
Transfer Karma
Previous · Next
User Message
patspam

Add a column to the userLoginLog table to record how long a user's session lasted and use this information to display a summary of user login times (in Admin Console -> Login History) and/or as a "total logged in time" display field inside a user's profile. 



Back to Top  
 
patspam

I found it was easy to achieve if you add 2 extra columns to userLoginLog: a sessionId and a lastPageViewed timestamp. If you arrange for lastPageViewed to be updated on every request (as per lastPageView in userSession) then you can determine the length of any session.

Here's my patch. I've bolded relevant sections where possible:

1. Add the extra columns to the database: 

alter table userLoginLog add column sessionId varchar(22);
alter table userLoginLog add column lastPageViewed int(11);


2. Modify the _logLogin function in Auth.pm (starts at line 94) so that the sessionId and current time (for lastPageViewed) get written to userLoginLog at user login:

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->session->getId,
        $self->session->datetime->time()]
        );
}
3. Add a single line to the www_viewLoginHistory function in Var.pm (at line 188) so that lastPageViewed gets updated:

$session->db->write("update userLoginLog set lastPageViewed=? where sessionId=?", [$session->datetime->time(), $sessionId]);


4. Modify the www_viewLoginHistory function in LoginHistory (starts at line 36) to display sessionId, lastPageViewed and Session Length along with other data in table:

sub www_viewLoginHistory {
    my $session = shift;
        return $session->privilege->adminOnly() unless ($session->user->isInGroup(3));
    my ($output, $p, @row, $i, $sth, %data);
    my $i18n = WebGUI::International->new($session);
    tie %data, 'Tie::CPHash';
    $sth = $session->db->read("select * from users,userLoginLog where users.userId=userLoginLog.userId order by userLoginLog.timeStamp desc");   
    while (%data = $sth->hash) {
        $data{username} = $i18n->get('unknown user') if ($data{userId} eq "0");
        $row[$i] = '<tr class="tableData"><td>'.$data{username}.' ('.$data{userId}.')</td>';
        $row[$i] .= '<td>'.$data{status}.'</td>';
        $row[$i] .= '<td>'.$session->datetime->epochToHuman($data{timeStamp},"%H:%n%p %M/%D/%y").'</td>';
        $row[$i] .= '<td>'.$data{ipAddress}.'</td>';
        $row[$i] .= '<td>'.$data{userAgent}.'</td>';
        $row[$i] .= '<td>'.$data{sessionId}.'</td>';
        if ($data{lastPageViewed}) {
            $row[$i] .= '<td>'.$session->datetime->epochToHuman($data{lastPageViewed},"%H:%n%p %M/%D/%y").'</td>';
            my ($interval, $units) = $session->datetime->secondsToInterval($data{lastPageViewed} - $data{timeStamp});
            $row[$i] .= "<td>$interval $units</td></tr>";
        } else {
            $row[$i] .= "<td></td>";
            $row[$i] .= "<td></td></tr>";
        }
        $i++;
    }
    $sth->finish;
    $p = WebGUI::Paginator->new($session,$session->url->page('op=viewLoginHistory'));
    $p->setDataByArrayRef(\@row);
    $output .= '<table border="1" cellpadding="5" cellspacing="0" align="center">';
    $output .= '<tr class="tableHeader"><td>'.$i18n->get(428).'</td>';
    $output .= '<td>'.$i18n->get(434).'</td>';
    $output .= '<td>'.$i18n->get(429).'</td>';
    $output .= '<td>'.$i18n->get(431).'</td>';
    $output .= '<td>'.$i18n->get(433).'</td>';
    $output .= '<td>Session ID</td>';
    $output .= '<td>Last Page Viewed</td>';
    $output .= '<td>Session Length</td></tr>';
        $output .= $p->getPage($session->form->process("pn"));
        $output .= '</table>';
        $output .= $p->getBar($session->form->process("pn"));
    return WebGUI::AdminConsole->new($session,"loginHistory")->render($output);
}

5. Modify the www_listUsers function in User (starts at line 554) to output lastPageViewed and Session Length along with other data in table:

sub www_listUsers {
    my $session = shift;
    unless ($session->user->isInGroup(3)) {
        if ($session->user->isInGroup(11)) {
            return www_editUser($session, undef, "new");
        }
        return $session->privilege->adminOnly();
    }
    my %status;
    my $i18n = WebGUI::International->new($session);
    my $output = getUserSearchForm($session,"listUsers");
    my ($userCount) = $session->db->quickArray("select count(*) from users");
    return _submenu($session,{workarea => $output}) unless ($session->form->process("doit") || $userCount<250 || $session->form->process("pn") > 1);
    tie %status, 'Tie::IxHash';
    %status = (
        Active        => $i18n->get(817),
        Deactivated    => $i18n->get(818),
        Selfdestructed    => $i18n->get(819)
    );
        $output .= '<table border="1" cellpadding="5" cellspacing="0" align="center">';
        $output .= '<tr>
                <td class="tableHeader">'.$i18n->get(816).'</td>
                <td class="tableHeader">'.$i18n->get(50).'</td>
                <td class="tableHeader">'.$i18n->get(56).'</td>
                <td class="tableHeader">'.$i18n->get(453).'</td>
                <td class="tableHeader">'.$i18n->get(454).'</td>
                <td class="tableHeader">'.$i18n->get(429).'</td>
                <td class="tableHeader">'.$i18n->get(434).'</td>
                <td class="tableHeader">Last Page Viewed</td>
                <td class="tableHeader">Session Length</td>
        </tr>';
    my $p = doUserSearch($session,"listUsers",1);
    foreach my $data (@{$p->getPageData}) {
        $output .= '<tr class="tableData">';
        $output .= '<td>'.$status{$data->{status}}.'</td>';
        $output .= '<td><a href="'.$session->url->page('op=editUser;uid='.$data->{userId})
            .'">'.$data->{username}.'</a></td>';
        $output .= '<td class="tableData">'.$data->{email}.'</td>';
        $output .= '<td class="tableData">'.$session->datetime->epochToHuman($data->{dateCreated},"%z").'</td>';
        $output .= '<td class="tableData">'.$session->datetime->epochToHuman($data->{lastUpdated},"%z").'</td>';
        my ($lastLoginStatus, $lastLogin, $lastPageViewed) = $session->db->quickArray("select status,timeStamp,lastPageViewed from userLoginLog where
                        userId=".$session->db->quote($data->{userId})." order by timeStamp DESC");
                if ($lastLogin) {
                        $output .= '<td class="tableData">'.$session->datetime->epochToHuman($lastLogin).'</td>';
                } else {
                        $output .= '<td class="tableData"> - </td>';
                }
                if ($lastLoginStatus) {
                        $output .= '<td class="tableData">'.$lastLoginStatus.'</td>';
                } else {
                        $output .= '<td class="tableData"> - </td>';
                }
                if ($lastPageViewed) {
                    $output .= '<td class="tableData"> '.$session->datetime->epochToHuman($lastPageViewed).'</td>';
                    my ($interval, $units) = $session->datetime->secondsToInterval($lastPageViewed - $lastLogin);
                    $output .= "<td class='tableData'>$interval $units</td></tr>";
                } else {
                    $output .= "<td class='tableData'> - </td>";
                    $output .= "<td class='tableData'> - </td></tr>";
                }
        $output .= '</tr>';
    }
        $output .= '</table>';
        $p->setAlphabeticalKey('username');
        $output .= $p->getBarTraditional;
    my $submenu = _submenu($session, { workarea => $output,
                       help => "users manage"
                     });
    return $submenu;
}

That's all. Some comments:

  • The session length information could be used in more places to display useful info such as totaly logged in time etc..
  • It's worth pointing out that I haven't used i18n variables for the column headers.
  • If you used this information to display total logged in time then you'd probably want to turn off the CleanLoginHistory workflow activity.

Cheers,

Patrick



Back to Top  
 
patspam

At preaction's suggestion on IRC, here it is as a SVN diff based on the latest source with the non-i18n variables using $i18n->echo().

Patrick 



Attached Files
Back to Top  
 
patspam

Updated as per email to dev list:

I've re-submitted the patch so that it doesn't require a db write per request. Instead of updating userLoginLog.lastPageViewed every request, the code now only updates lastPageViewed when sessions expire (via the DeleteExpiredSessions workflow) and when users log in. This means that the User List's "Total Recorded Time" no longer updates in real-time, but you still end up with the same values as before (excluding active sessions) which is probably not a bad trade-off for the performance increase.

Patrick 



Attached Files
Back to Top  
 
JT
Sounds like a great compromise. Approved to be added in 7.4.

Back to Top  
 
patspam
Removed debug statements from DeleteExpiredSessions activity.


Attached Files
Back to Top