Add Passive Analytics modules, Workflow Activites, i18n and content
handler.
This commit is contained in:
parent
d59cdea8a7
commit
eb844fd26e
6 changed files with 790 additions and 0 deletions
49
lib/WebGUI/Content/PassiveAnalytics.pm
Normal file
49
lib/WebGUI/Content/PassiveAnalytics.pm
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
package WebGUI::Content::PassiveAnalytics;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use WebGUI::AdminConsole;
|
||||||
|
use WebGUI::Exception;
|
||||||
|
use WebGUI::PassiveAnalytics::Flow;
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Package WebGUI::Content::PassiveAnalytics
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Handle all requests for building and editing Passive Analytic flows.
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use WebGUI::Content::PassiveAnalytics;
|
||||||
|
my $output = WebGUI::Content::PassiveAnalytics::handler($session);
|
||||||
|
|
||||||
|
=head1 SUBROUTINES
|
||||||
|
|
||||||
|
These subroutines are available from this package:
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 handler ( session )
|
||||||
|
|
||||||
|
The content handler for this package.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub handler {
|
||||||
|
my ($session) = @_;
|
||||||
|
my $output = undef;
|
||||||
|
return undef unless $session->form->get('op') eq 'passiveAnalytics';
|
||||||
|
my $function = "www_".$session->form->get('func');
|
||||||
|
if ($function ne "www_" && (my $sub = WebGUI::PassiveAnalytics::Flow->can($function))) {
|
||||||
|
$output = $sub->($session);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WebGUI::Error::MethodNotFound->throw(error=>"Couldn't call non-existant method $function inside PassiveAnalytics", method=>$function);
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
254
lib/WebGUI/PassiveAnalytics/Flow.pm
Normal file
254
lib/WebGUI/PassiveAnalytics/Flow.pm
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
package WebGUI::PassiveAnalytics::Flow;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Tie::IxHash;
|
||||||
|
use WebGUI::AdminConsole;
|
||||||
|
use WebGUI::HTMLForm;
|
||||||
|
use WebGUI::International;
|
||||||
|
use WebGUI::Pluggable;
|
||||||
|
use WebGUI::PassiveAnalytics::Rule;
|
||||||
|
use WebGUI::Utility;
|
||||||
|
use WebGUI::HTMLForm;
|
||||||
|
use WebGUI::Workflow;
|
||||||
|
use WebGUI::Workflow::Instance;
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Package WebGUI::PassiveAnalytics::Flow
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Web interface for making sets of rules for doing passive analytics, and
|
||||||
|
running them.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 canView ( session [, user] )
|
||||||
|
|
||||||
|
Returns true if the user can administrate this operation. user defaults to
|
||||||
|
the current user.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub canView {
|
||||||
|
my $session = shift;
|
||||||
|
my $user = shift || $session->user;
|
||||||
|
return $user->isInGroup( 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 www_deleteRule ( )
|
||||||
|
|
||||||
|
Deletes an activity from a workflow.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub www_deleteRule {
|
||||||
|
my $session = shift;
|
||||||
|
return $session->privilege->insufficient() unless canView($session);
|
||||||
|
my $rule = WebGUI::PassiveAnalytics::Rule->new($session, $session->form->get("ruleId"));
|
||||||
|
if (defined $rule) {
|
||||||
|
$rule->delete;
|
||||||
|
}
|
||||||
|
return www_editRuleflow($session);
|
||||||
|
}
|
||||||
|
|
||||||
|
#------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 www_demoteRule ( session )
|
||||||
|
|
||||||
|
Moves a Rule down one position in the execution order.
|
||||||
|
|
||||||
|
=head3 session
|
||||||
|
|
||||||
|
A reference to the current session.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub www_demoteRule {
|
||||||
|
my $session = shift;
|
||||||
|
return $session->privilege->insufficient() unless canView($session);
|
||||||
|
my $rule = WebGUI::PassiveAnalytics::Rule->new($session, $session->form->get("ruleId"));
|
||||||
|
if (defined $rule) {
|
||||||
|
$rule->demote;
|
||||||
|
}
|
||||||
|
return www_editRuleflow($session);
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 www_editRuleflow ( session )
|
||||||
|
|
||||||
|
Configure a set of analyses to run on the passive logs. The analysis is destructive.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub www_editRuleflow {
|
||||||
|
my $session = shift;
|
||||||
|
my $error = shift;
|
||||||
|
return $session->privilege->insufficient() unless canView($session);
|
||||||
|
if ($error) {
|
||||||
|
$error = qq|<div class="error">$error</div>\n|;
|
||||||
|
}
|
||||||
|
my $i18n = WebGUI::International->new($session, "PassiveAnalytics");
|
||||||
|
my $addmenu = '<div style="float: left; width: 200px; font-size: 11px;">';
|
||||||
|
$addmenu .= sprintf '<a href="%s">%s</a>',
|
||||||
|
$session->url->page('op=passiveAnalytics;func=editRule'),
|
||||||
|
$i18n->get('Add a bucket');
|
||||||
|
$addmenu .= '</div>';
|
||||||
|
my $f = WebGUI::HTMLForm->new($session);
|
||||||
|
$f->hidden(
|
||||||
|
name=>'op',
|
||||||
|
value=>'passiveAnalytics'
|
||||||
|
);
|
||||||
|
$f->hidden(
|
||||||
|
name=>'func',
|
||||||
|
value=>'editRuleflowSave'
|
||||||
|
);
|
||||||
|
$f->integer(
|
||||||
|
name => 'pauseInterval',
|
||||||
|
value => 300,
|
||||||
|
label => $i18n->get('pause interval'),
|
||||||
|
hoverHelp => $i18n->get('pause interval help'),
|
||||||
|
);
|
||||||
|
$f->submit(value => $i18n->get('Begin analysis'));
|
||||||
|
my $steps = '<table class="content"><tbody>';
|
||||||
|
my $getARule = WebGUI::PassiveAnalytics::Rule->getAllIterator($session);
|
||||||
|
my $icon = $session->icon;
|
||||||
|
while (my $rule = $getARule->()) {
|
||||||
|
my $id = $rule->getId;
|
||||||
|
my $bucket = $rule->get('bucketName');
|
||||||
|
$steps .= '<tr><td>'
|
||||||
|
. $icon->delete( 'op=passiveAnalytics;func=deleteRule;ruleId='.$id, undef, $i18n->get('confirm delete rule'))
|
||||||
|
. $icon->edit( 'op=passiveAnalytics;func=editRule;ruleId='.$id)
|
||||||
|
. $icon->moveDown('op=passiveAnalytics;func=demoteRule;ruleId='.$id)
|
||||||
|
. $icon->moveUp( 'op=passiveAnalytics;func=promoteRule;ruleId='.$id)
|
||||||
|
. '</td><td>'.$bucket.'</td></tr>';
|
||||||
|
|
||||||
|
}
|
||||||
|
$steps .= '<tr><td> </td><td>Other</td></tbody></table><div style="clear: both;"></div>';
|
||||||
|
my $ac = WebGUI::AdminConsole->new($session,'passiveAnalytics');
|
||||||
|
return $ac->render($error.$f->print.$addmenu.$steps, 'Passive Analytics');
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 www_editRuleflowSave ( )
|
||||||
|
|
||||||
|
Saves the results of www_editRuleflow()
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub www_editRuleflowSave {
|
||||||
|
my $session = shift;
|
||||||
|
return $session->privilege->insufficient() unless canView($session);
|
||||||
|
my $workflow = WebGUI::Workflow->new($session, 'PassiveAnalytics000001');
|
||||||
|
return www_editRuleflow($session, "The Passive Analytics workflow has been deleted. Please contact an Administrator immediately.") unless defined $workflow;
|
||||||
|
my $delta = $session->form->process('pauseInterval','integer');
|
||||||
|
my $activities = $workflow->getActivities();
|
||||||
|
##Note, they're in order, and the order is known.
|
||||||
|
$activities->[0]->set('deltaInterval', $delta);
|
||||||
|
$activities->[1]->set('userId', $session->user->userId);
|
||||||
|
my $instance = WebGUI::Workflow::Instance->create($session, {
|
||||||
|
workflowId => $workflow->getId,
|
||||||
|
priority => 1,
|
||||||
|
});
|
||||||
|
if (!defined $instance) {
|
||||||
|
return www_editRuleflow($session, "A Passive Analytics analysis is currently running.") if $session->stow->get('singletonWorkflowClash');
|
||||||
|
return www_editRuleflow($session, "Error creating the workflow instance.");
|
||||||
|
}
|
||||||
|
$instance->start('skipRealtime');
|
||||||
|
return www_editRuleflow($session, "Passive Analytics session started");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 www_editRule ( )
|
||||||
|
|
||||||
|
Displays a form to edit the properties rule.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub www_editRule {
|
||||||
|
my $session = shift;
|
||||||
|
return $session->privilege->insufficient() unless canView($session);
|
||||||
|
|
||||||
|
##Make a PassiveAnalytics rule to use to populate the form.
|
||||||
|
my $ruleId = $session->form->get('ruleId');
|
||||||
|
my $rule;
|
||||||
|
if ($ruleId) {
|
||||||
|
$rule = WebGUI::PassiveAnalytics::Rule->new($session, $ruleId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
##We need a temporary rule so that we can call dynamicForm, below
|
||||||
|
$ruleId = 'new';
|
||||||
|
$rule = WebGUI::PassiveAnalytics::Rule->create($session, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
##Build the form
|
||||||
|
my $form = WebGUI::HTMLForm->new($session);
|
||||||
|
$form->hidden( name=>"op", value=>"passiveAnalytics");
|
||||||
|
$form->hidden( name=>"func", value=>"editRuleSave");
|
||||||
|
$form->hidden( name=>"ruleId", value=>$ruleId);
|
||||||
|
$form->dynamicForm([WebGUI::PassiveAnalytics::Rule->crud_definition($session)], 'properties', $rule);
|
||||||
|
$form->submit;
|
||||||
|
|
||||||
|
my $i18n = WebGUI::International->new($session, 'PassiveAnalytics');
|
||||||
|
my $ac = WebGUI::AdminConsole->new($session,'passiveAnalytics');
|
||||||
|
$ac->addSubmenuItem($session->url->page("op=passiveAnalytics;func=editRuleflow"), $i18n->get("manage ruleset"));
|
||||||
|
if ($ruleId eq 'new') {
|
||||||
|
$rule->delete;
|
||||||
|
}
|
||||||
|
return $ac->render($form->print,$i18n->get('Edit Rule'));
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 www_editRuleSave ( )
|
||||||
|
|
||||||
|
Saves the results of www_editRule().
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub www_editRuleSave {
|
||||||
|
my $session = shift;
|
||||||
|
return $session->privilege->insufficient() unless canView($session);
|
||||||
|
my $ruleId = $session->form->get('ruleId');
|
||||||
|
my $rule;
|
||||||
|
if ($ruleId eq 'new') {
|
||||||
|
$rule = WebGUI::PassiveAnalytics::Rule->create($session, {});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$rule = WebGUI::PassiveAnalytics::Rule->new($session, $ruleId);
|
||||||
|
}
|
||||||
|
$rule->updateFromFormPost if $rule;
|
||||||
|
return www_editRuleflow($session);
|
||||||
|
}
|
||||||
|
|
||||||
|
#------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 www_promoteRule ( session )
|
||||||
|
|
||||||
|
Moves a rule up one position in the execution order.
|
||||||
|
|
||||||
|
=head3 session
|
||||||
|
|
||||||
|
A reference to the current session.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub www_promoteRule {
|
||||||
|
my $session = shift;
|
||||||
|
return $session->privilege->insufficient() unless canView($session);
|
||||||
|
my $rule = WebGUI::PassiveAnalytics::Rule->new($session, $session->form->get("ruleId"));
|
||||||
|
if (defined $rule) {
|
||||||
|
$rule->promote;
|
||||||
|
}
|
||||||
|
return www_editRuleflow($session);
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
92
lib/WebGUI/PassiveAnalytics/Rule.pm
Normal file
92
lib/WebGUI/PassiveAnalytics/Rule.pm
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
package WebGUI::PassiveAnalytics::Rule;
|
||||||
|
|
||||||
|
use base qw/WebGUI::Crud/;
|
||||||
|
use WebGUI::International;
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Package WebGUI::PassiveAnalytics::Rule;
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Base class for rules that are used to analyze the Passive Analytics log.
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
These methods are available from this class:
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 crud_definition ( )
|
||||||
|
|
||||||
|
WebGUI::Crud definition for this class.
|
||||||
|
|
||||||
|
=head3 tableName
|
||||||
|
|
||||||
|
analyticRule.
|
||||||
|
|
||||||
|
=head3 tableKey
|
||||||
|
|
||||||
|
ruleId
|
||||||
|
|
||||||
|
=head3 sequenceKey
|
||||||
|
|
||||||
|
None. There is only 1 sequence of rules for a site.
|
||||||
|
|
||||||
|
=head3 properties
|
||||||
|
|
||||||
|
=head4 bucketName
|
||||||
|
|
||||||
|
The name of a bucket to hold results for this rule.
|
||||||
|
|
||||||
|
=head4 rules
|
||||||
|
|
||||||
|
JSON blob with configuration data for the individual rules.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub crud_definition {
|
||||||
|
my ($class, $session) = @_;
|
||||||
|
my $definition = $class->SUPER::crud_definition($session);
|
||||||
|
$definition->{tableName} = 'analyticRule';
|
||||||
|
$definition->{tableKey} = 'ruleId';
|
||||||
|
$definition->{sequenceKey} = '';
|
||||||
|
my $properties = $definition->{properties};
|
||||||
|
my $i18n = WebGUI::International->new($session);
|
||||||
|
$properties->{bucketName} = {
|
||||||
|
fieldType => 'text',
|
||||||
|
label => $i18n->get('Bucket Name','PassiveAnalytics'),
|
||||||
|
hoverHelp => $i18n->get('Bucket Name help','PassiveAnalytics'),
|
||||||
|
defaultValue => '',
|
||||||
|
};
|
||||||
|
$properties->{regexp} = {
|
||||||
|
fieldType => 'text',
|
||||||
|
label => $i18n->get('regexp','PassiveAnalytics'),
|
||||||
|
hoverHelp => $i18n->get('regexp help','PassiveAnalytics'),
|
||||||
|
defaultValue => '.+',
|
||||||
|
};
|
||||||
|
return $definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 matchesBucket ( $logLine )
|
||||||
|
|
||||||
|
Executes the rule to determine if a log file entry matches the rule.
|
||||||
|
|
||||||
|
=head3 $logLine
|
||||||
|
|
||||||
|
A hashref of information from 1 line of the logs.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub matchesBucket {
|
||||||
|
my ($self, $logLine) = @_;
|
||||||
|
my $regexp = $self->get('regexp');
|
||||||
|
return $logLine->{url} =~ m/$regexp/;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
#vim:ft=perl
|
||||||
138
lib/WebGUI/Workflow/Activity/BucketPassiveAnalytics.pm
Normal file
138
lib/WebGUI/Workflow/Activity/BucketPassiveAnalytics.pm
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
package WebGUI::Workflow::Activity::BucketPassiveAnalytics;
|
||||||
|
|
||||||
|
|
||||||
|
=head1 LEGAL
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Copyright 2001-2008 SDH Corporation
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use base 'WebGUI::Workflow::Activity';
|
||||||
|
use WebGUI::PassiveAnalytics::Rule;
|
||||||
|
use WebGUI::Inbox;
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Package WebGUI::Workflow::Activity::BucketPassiveAnalytics
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Run through a set of rules to figure out how to classify log file entries.
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
See WebGUI::Workflow::Activity for details on how to use any activity.
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
These methods are available from this class:
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 definition ( session, definition )
|
||||||
|
|
||||||
|
See WebGUI::Workflow::Activity::defintion() for details.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub definition {
|
||||||
|
my $class = shift;
|
||||||
|
my $session = shift;
|
||||||
|
my $definition = shift;
|
||||||
|
my $i18n = WebGUI::International->new($session, "PassiveAnalytics");
|
||||||
|
push( @{$definition}, {
|
||||||
|
name=>$i18n->get("Bucket Passive Analytics"),
|
||||||
|
properties=> {
|
||||||
|
notifyUser => {
|
||||||
|
fieldType => 'user',
|
||||||
|
label => $i18n->get('User'),
|
||||||
|
hoverHelp => $i18n->get('User help'),
|
||||||
|
defaultValue => $session->user->userId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return $class->SUPER::definition($session,$definition);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 execute ( [ object ] )
|
||||||
|
|
||||||
|
Analyze the deltaLog table, and generate the bucketLog table.
|
||||||
|
|
||||||
|
=head3 notes
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub execute {
|
||||||
|
my ($self, undef, $instance) = @_;
|
||||||
|
my $session = $self->session;
|
||||||
|
my $endTime = time() + $self->getTTL;
|
||||||
|
my $expired = 0;
|
||||||
|
|
||||||
|
##Load all the rules into an array
|
||||||
|
my @rules = ();
|
||||||
|
my $getARule = WebGUI::PassiveAnalytics::Rule->getAllIterator($session);
|
||||||
|
while (my $rule = $getARule->()) {
|
||||||
|
push @rules, $rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
##Get the index stored from the last invocation of the Activity. If this is
|
||||||
|
##the first run, then clear out the table.
|
||||||
|
my $logIndex = $instance->getScratch('lastPassiveLogIndex') || 0;
|
||||||
|
if ($logIndex == 0) {
|
||||||
|
$session->db->write('delete from bucketLog');
|
||||||
|
}
|
||||||
|
|
||||||
|
##Configure all the SQL
|
||||||
|
my $deltaSql = <<"EOSQL1";
|
||||||
|
select userId, assetId, url, delta, from_unixtime(timeStamp) as stamp
|
||||||
|
from deltaLog order by timestamp limit $logIndex, 1234567890
|
||||||
|
EOSQL1
|
||||||
|
my $deltaSth = $session->db->read($deltaSql);
|
||||||
|
my $bucketSth = $session->db->prepare('insert into bucketLog (userId, Bucket, duration, timeStamp) VALUES (?,?,?,?)');
|
||||||
|
|
||||||
|
##Walk through the log file entries, one by one. Run each entry against
|
||||||
|
##all the rules until 1 matches. If it doesn't match any rule, then bin it
|
||||||
|
##into the "Other" bucket.
|
||||||
|
DELTA_ENTRY: while (my $entry = $deltaSth->hashRef()) {
|
||||||
|
++$logIndex;
|
||||||
|
my $bucketFound = 0;
|
||||||
|
RULE: foreach my $rule (@rules) {
|
||||||
|
next RULE unless $rule->matchesBucket($entry);
|
||||||
|
$bucketSth->execute([$entry->{userId}, $rule->get('bucketName'), $entry->{delta}, $entry->{stamp}]);
|
||||||
|
}
|
||||||
|
if (!$bucketFound) {
|
||||||
|
$bucketSth->execute([$entry->{userId}, 'Other', $entry->{delta}, $entry->{stamp}]);
|
||||||
|
}
|
||||||
|
if (time() > $endTime) {
|
||||||
|
$expired = 1;
|
||||||
|
last DELTA_ENTRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($expired) {
|
||||||
|
$instance->setScratch('logIndex', $logIndex);
|
||||||
|
return $self->WAITING(1);
|
||||||
|
}
|
||||||
|
my $inbox = WebGUI::Inbox->new($self->session);
|
||||||
|
$inbox->addMessage({
|
||||||
|
status => 'unread',
|
||||||
|
subject => 'Passive analytics is done',
|
||||||
|
userId => $self->get('userId'),
|
||||||
|
message => 'Passive analytics is done',
|
||||||
|
});
|
||||||
|
|
||||||
|
return $self->COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
#vim:ft=perl
|
||||||
158
lib/WebGUI/Workflow/Activity/SummarizePassiveAnalytics.pm
Normal file
158
lib/WebGUI/Workflow/Activity/SummarizePassiveAnalytics.pm
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
package WebGUI::Workflow::Activity::SummarizePassiveAnalytics;
|
||||||
|
|
||||||
|
|
||||||
|
=head1 LEGAL
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Copyright 2001-2008 SDH Corporation
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use base 'WebGUI::Workflow::Activity';
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Package WebGUI::Workflow::Activity::SummarizePassiveAnalytics
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Summarize how long a user stayed on a page, using a user supplied interval.
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
See WebGUI::Workflow::Activity for details on how to use any activity.
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
These methods are available from this class:
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 definition ( session, definition )
|
||||||
|
|
||||||
|
See WebGUI::Workflow::Activity::defintion() for details.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub definition {
|
||||||
|
my $class = shift;
|
||||||
|
my $session = shift;
|
||||||
|
my $definition = shift;
|
||||||
|
my $i18n = WebGUI::International->new($session, 'PassiveAnalytics');
|
||||||
|
push(@{$definition}, {
|
||||||
|
name=>$i18n->get('activityName'),
|
||||||
|
properties=> {
|
||||||
|
deltaInterval => {
|
||||||
|
fieldType => 'interval',
|
||||||
|
label => $i18n->get('pause interval'),
|
||||||
|
defaultValue => 15,
|
||||||
|
hoverHelp => $i18n->get('pause interval help'),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return $class->SUPER::definition($session,$definition);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------
|
||||||
|
|
||||||
|
=head2 execute ( [ object ] )
|
||||||
|
|
||||||
|
Analyze the passiveLog table, and generate the deltaLog table.
|
||||||
|
|
||||||
|
=head3 notes
|
||||||
|
|
||||||
|
If there is only 1 line in the table for a particular sessionId or
|
||||||
|
userId, no conclusions as to how long the user viewed a page can be
|
||||||
|
drawn from that. Similarly, the last entry in their browsing log
|
||||||
|
yields no data, since we require another entry in the passiveLog to
|
||||||
|
determine a delta.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub execute {
|
||||||
|
my ($self, undef, $instance) = @_;
|
||||||
|
my $session = $self->session;
|
||||||
|
my $endTime = time() + $self->getTTL;
|
||||||
|
my $deltaInterval = $self->get('deltaInterval');
|
||||||
|
|
||||||
|
my $passive = 'select * from passiveLog where userId <> 1 order by userId, sessionId, timeStamp';
|
||||||
|
my $sth;
|
||||||
|
my $lastUserId;
|
||||||
|
my $lastSessionId;
|
||||||
|
my $lastTimeStamp;
|
||||||
|
my $lastAssetId;
|
||||||
|
my $lastUrl;
|
||||||
|
my $counter = $instance->getScratch('counter');
|
||||||
|
if ($counter) {
|
||||||
|
$passive .= ' limit '. $counter .', 1234567890';
|
||||||
|
$sth = $session->db->read($passive);
|
||||||
|
$lastUserId = $instance->getScratch('lastUserId');
|
||||||
|
$lastSessionId = $instance->getScratch('lastSessionId');
|
||||||
|
$lastTimeStamp = $instance->getScratch('lastTimeStamp');
|
||||||
|
$lastAssetId = $instance->getScratch('lastAssetId');
|
||||||
|
$lastUrl = $instance->getScratch('lastUrl');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$sth = $session->db->read($passive);
|
||||||
|
my $logLine = $sth->hashRef();
|
||||||
|
$logLine = $sth->hashRef();
|
||||||
|
$lastUserId = $logLine->{userId};
|
||||||
|
$lastSessionId = $logLine->{sessionId};
|
||||||
|
$lastTimeStamp = $logLine->{timeStamp};
|
||||||
|
$lastAssetId = $logLine->{assetId};
|
||||||
|
$lastUrl = $logLine->{url};
|
||||||
|
}
|
||||||
|
|
||||||
|
$session->db->write('delete from deltaLog'); ##Only if we're starting out
|
||||||
|
my $deltaLog = $session->db->prepare('insert into deltaLog (userId, assetId, delta, timeStamp, url) VALUES (?,?,?,?,?)');
|
||||||
|
|
||||||
|
my $expired = 0;
|
||||||
|
LOG_ENTRY: while (my $logLine = $sth->hashRef()) {
|
||||||
|
$counter++;
|
||||||
|
my $delta = $logLine->{timeStamp} - $lastTimeStamp;
|
||||||
|
if ( $logLine->{userId} eq $lastUserId
|
||||||
|
&& $logLine->{sessionId} eq $lastSessionId
|
||||||
|
&& $delta < $deltaInterval ) {
|
||||||
|
$deltaLog->execute([$lastUserId, $lastAssetId, $delta, $lastTimeStamp, $lastUrl]);
|
||||||
|
}
|
||||||
|
$lastUserId = $logLine->{userId};
|
||||||
|
$lastSessionId = $logLine->{sessionId};
|
||||||
|
$lastTimeStamp = $logLine->{timeStamp};
|
||||||
|
$lastAssetId = $logLine->{assetId};
|
||||||
|
$lastUrl = $logLine->{url};
|
||||||
|
if (time() > $endTime) {
|
||||||
|
$instance->setScratch('lastUserId', $lastUserId);
|
||||||
|
$instance->setScratch('lastSessionId', $lastSessionId);
|
||||||
|
$instance->setScratch('lastTimeStamp', $lastTimeStamp);
|
||||||
|
$instance->setScratch('lastAssetId', $lastAssetId);
|
||||||
|
$instance->setScratch('lastUrl', $lastUrl);
|
||||||
|
$instance->setScratch('counter', $counter);
|
||||||
|
$expired = 1;
|
||||||
|
last LOG_ENTRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($expired) {
|
||||||
|
return $self->WAITING(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$instance->deleteScratch('lastUserId');
|
||||||
|
$instance->deleteScratch('lastSessionId');
|
||||||
|
$instance->deleteScratch('lastTimeStamp');
|
||||||
|
$instance->deleteScratch('lastAssetId');
|
||||||
|
$instance->deleteScratch('lastUrl');
|
||||||
|
$instance->deleteScratch('counter');
|
||||||
|
return $self->COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
#vim:ft=perl
|
||||||
99
lib/WebGUI/i18n/English/PassiveAnalytics.pm
Normal file
99
lib/WebGUI/i18n/English/PassiveAnalytics.pm
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
package WebGUI::i18n::English::PassiveAnalytics;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
our $I18N = {
|
||||||
|
|
||||||
|
'Summarize Passive Analytics' => {
|
||||||
|
message => q|Summarize Passive Analytics|,
|
||||||
|
context => q|The name of this workflow activity.|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
'pause interval' => {
|
||||||
|
message => q|Pause threshold|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
'pause interval help' => {
|
||||||
|
message => q|Set the time between clicks that is interpreted as the user reading the page, as opposed to beginning a new browsing session, or leaving the site.|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
'other' => {
|
||||||
|
message => q|Other|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|Meaning not like anything in a set. This, that and the other one. Also, a catch all.|
|
||||||
|
},
|
||||||
|
|
||||||
|
'Bucket Name' => {
|
||||||
|
message => q|Bucket Name|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|To name a container, or bucket.|
|
||||||
|
},
|
||||||
|
|
||||||
|
'Bucket Name help' => {
|
||||||
|
message => q|Pick a unique, descriptive short name for this bucket.|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q||
|
||||||
|
},
|
||||||
|
|
||||||
|
'regexp' => {
|
||||||
|
message => q|Regular expression|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q||
|
||||||
|
},
|
||||||
|
|
||||||
|
'regexp help' => {
|
||||||
|
message => q|Define a regular expression to pick log entries for this bucket.<br />
|
||||||
|
^ = beginning of url<br />
|
||||||
|
$ = end of url<br />
|
||||||
|
. = any character<br />
|
||||||
|
* = any amount<br />
|
||||||
|
+ = 1 or more<br />
|
||||||
|
? = 0 or 1<br />
|
||||||
|
|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q||
|
||||||
|
},
|
||||||
|
|
||||||
|
'Passive Analytics' => {
|
||||||
|
message => q|Passive Analytics|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q||
|
||||||
|
},
|
||||||
|
|
||||||
|
'Edit Rule' => {
|
||||||
|
message => q|Edit Rule|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q||
|
||||||
|
},
|
||||||
|
|
||||||
|
'Add a bucket' => {
|
||||||
|
message => q|Add a bucket|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q||
|
||||||
|
},
|
||||||
|
|
||||||
|
'User' => {
|
||||||
|
message => q|User|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q||
|
||||||
|
},
|
||||||
|
|
||||||
|
'User help' => {
|
||||||
|
message => q|The user who will recieve an email when bucket processing is done.|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q||
|
||||||
|
},
|
||||||
|
|
||||||
|
'Begin analysis' => {
|
||||||
|
message => q|Begin analysis|,
|
||||||
|
lastUpdated => 0,
|
||||||
|
context => q|Button label to begin analyzing the logs.|
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
1;
|
||||||
|
#vim:ft=perl
|
||||||
Loading…
Add table
Add a link
Reference in a new issue