webgui/lib/WebGUI/Macro/UsersOnline.pm

297 lines
8.8 KiB
Perl

package WebGUI::Macro::UsersOnline;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2009 Plain Black LLC.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
http://www.plainblack.com info@plainblack.com
-------------------------------------------------------------------
Authors of Macro:
Carlos Rivero (http://www.carlosrivero.com),
Bernd Kalbfuss-Zimmermann
-------------------------------------------------------------------
=cut
use strict;
use Apache2::ServerRec;
use Net::DNS;
use WebGUI::Asset::Template;
use WebGUI::International;
use WebGUI::Session::DateTime;
use WebGUI::SQL;
use WebGUI::User;
=head1 NAME
Package WebGUI::Macro::UsersOnline;
=head1 DESCRIPTION
Macro for displaying users that are online.
=cut
#-------------------------------------------------------------------
=head2 process ( [templateId], [minutes], [maxMembers], [maxVisitors] )
Returns a fragment of HTML code showing the number of users online. Appearance
can be altered by specifying an alternative template.
=head3 templateId
The ID of the template to be processed. The default is 'h_T2xtOxGRQ9QJOR6ebLpQ'.
=head3 minutes
The number of minutes the last activity may date back for a user to count as
online.cThe default is 5 minutes.
=head3 maxMembers
The maximum number of members to be returned in the members template loop. The
default is 10.
=head3 maxVisitors
The maximum number of visitors to be returned in the visitors template loop. The
default is 10.
=cut
sub process {
# Assign parameters
my $session = shift;
my $templateId = shift;
my $minutes = shift;
my $maxMembers = shift;
my $maxVisitors = shift;
# Assign default values
$templateId ||= "h_T2xtOxGRQ9QJOR6ebLpQ";
$minutes = 5 unless defined $minutes;
$maxMembers = 10 unless defined $maxMembers;
$maxVisitors = 10 unless defined $maxVisitors;
# Create hash of template variables
my %var;
# Obtain internationalization instance
my $i18n = WebGUI::International->new($session, "Macro_UsersOnline");
# Get preferred time format of current user
my $time_format = $session->user->profileField("timeFormat");
# Calculate epoch time for comparison to last activity
my $dt = $session->datetime;
my $epoch = $dt->time();
$epoch = $session->datetime->addToTime($epoch, 0, -$minutes, 0);
# Let private subroutines do the work
_visitors($session, \%var, $epoch, $maxVisitors);
_members($session, \%var, $epoch, $maxMembers);
# Calculate the total number of active users
$var{'total'} = $var{'members'} + $var{'visitors'};
# Set some flags
$var{'isVisitor'} = 1 if ($session->user->isVisitor);
$var{'hasMembers'} = 1 if $var{'member_loop'};
# Assign labels
$var{'usersOnline_label'} = $i18n->get("Users Online");
$var{'members_label'} = $i18n->get("Members");
$var{'visitors_label'} = $i18n->get("Visitors");
$var{'total_label'} = $i18n->get("Total");
$var{'membersOnline_label'} = $i18n->get("Members Online");
$var{'visitorsOnline_label'} = $i18n->get("Visitors Online");
$var{'avatar_label'} = $i18n->get("Avatar");
$var{'name_label'} = $i18n->get("Name");
$var{'alias_label'} = $i18n->get("Alias");
$var{'session_label'} = $i18n->get("Session");
$var{'ip_label'} = $i18n->get("IP");
$var{'lastActivity_label'} = $i18n->get("Last Activity");
# Process Template
return WebGUI::Asset::Template->new($session,$templateId)->process(\%var);
}
#-------------------------------------------------------------------
=head2 _visitors ( session, varRef, epoch, maxVisitors )
Fills template variables concerning visitors, i.e. the number of visitors and
all variables in the visitors loop. Private subroutine used by process().
=head3 session
A reference to the current session.
=head3 varRef
A reference to the hash of template variables.
=head3 epoch
Epoch time for comparison to last activity.
=head3 maxVisitors
The maximum number of visitors to be returned in the visitors template loop.
=cut
sub _visitors {
# Assign parameters
my $session = shift;
my $var = shift;
my $epoch = shift;
my $maxVisitors = shift;
# Obtain some session-associated objects
my $db = $session->db();
my $dt = $session->datetime;
# Get preferred time format of current user
my $time_format = $session->user->profileField("timeFormat");
# SQL conditional clause for filtering server IP
my $ip_clause;
# Check whether instance of Apache2::ServerRec is available
if($session->server) {
# Query hostname of server
my $hostname = $session->server->server_hostname();
# Look up server IP addresses
my $res = Net::DNS::Resolver->new();
my $query = $res->search($hostname);
if ($query) {
foreach my $rr ($query->answer) {
next unless $rr->type eq "A";
# Generate SQL clause which excludes server IPs
$ip_clause = $ip_clause . "AND STRCMP(lastIp, '" . $rr->address . "') ";
}
}
}
# Determine the number of visitors. Server IP adresses and the loopback
# network are excluded. We only count IPs - not sessions. The reason is
# that crawlers tend to open multiple sessions(e.g. googlebot) and thereby
# increase the count artificially. Note, that the number determined here
# may deviate from the number of items returned in the visitor loop.
$var->{'visitors'} = $db->quickScalar("SELECT COUNT(DISTINCT lastIp) FROM " .
"userSession WHERE (lastPageView > ?) AND (userId = 1) AND " .
"lastIp NOT LIKE '127.%.%.%'" . $ip_clause, [$epoch]);
# Query session IDs and IPs of visitors
my $query = $db->read("SELECT sessionId, lastIp, lastPageView FROM " .
"userSession WHERE (lastPageView > ?) AND (userId = 1) AND " .
"lastIp NOT LIKE '127.%.%.%' " . $ip_clause . "LIMIT ?", [$epoch, $maxVisitors]);
# Iterate through rows
while (my %row = $query->hash) {
# Add item to visitor template loop
push(@{$var->{'visitor_loop'}}, {
sessionId => $row{'sessionId'},
ip => $row{'lastIp'},
lastActivity => $dt->epochToHuman($row{'lastPageView'}, $time_format)
});
}
return;
}
#-------------------------------------------------------------------
=head2 _members ( session, varRef, epoch, maxMembers )
Fills template variables concerning members, i.e. the number of members and
all variables in the members loop. Private subroutine used by process().
=head3 session
A reference to the current session.
=head3 varRef
A reference to the hash of template variables.
=head3 epoch
Epoch time for comparison to last activity.
=head3 maxMembers
The maximum number of members to be returned in the members template loop.
=cut
sub _members {
# Assign parameters
my $session = shift;
my $var = shift;
my $epoch = shift;
my $maxMembers = shift;
# Obtain some session-associated objects
my $db = $session->db();
my $dt = $session->datetime;
# Get preferred time format of current user
my $time_format = $session->user->profileField("timeFormat");
# Determine the number of registered users that are online. The Admin
# account is excluded from the list.
$var->{'members'} = $db->quickScalar("SELECT COUNT(DISTINCT userId) FROM " .
"userSession where (lastPageView > ?) and (userId != '1') and " .
"(userId != '3')", [$epoch]);
# Query the names of registered users that are online. The showOnline flag
# in the user profile is respected.
my $query = $db->read("SELECT userId, sessionId, lastIp, lastPageView " .
"FROM userSession WHERE (lastPageView > ?) AND (userId != '1') " .
"AND (userId != '3') LIMIT ?", [$epoch, $maxMembers]);
# Iterate through rows
while (my %row = $query->hash) {
# Create instance of WebGUI::User for the user id from the current row
my $user = WebGUI::User->new($session, $row{'userId'});
# Only show users with the "showOnline" flag set to true
if ($user->profileField("showOnline")) {
# Find URL of avatar if available
my $avatar_url;
my $avatar = $user->profileField("avatar");
if ($avatar) {
my $storage = WebGUI::Storage->get($session, $avatar);
my @files = @{ $storage->getFiles() };
# We assume it is the first file in the storage. But maybe
# that is incorrect?
$avatar_url = $storage->getUrl($files[0]);
}
# Add item to member template loop
push(@{$var->{'member_loop'}}, {
username => $user->username(),
firstName => $user->profileField("firstName"),
middleName => $user->profileField("middleName"),
lastName => $user->profileField("lastName"),
alias => $user->profileField("alias"),
avatar => $avatar_url,
uid => $row{'userId'},
sessionId => $row{'sessionId'},
ip => $row{'lastIp'},
lastActivity => $dt->epochToHuman($row{'lastPageView'}, $time_format)
});
}
}
return;
}
1;