From cb5207c26894d034fdb8a6f7bb9bbd436be120df Mon Sep 17 00:00:00 2001 From: Stephen Opal Date: Wed, 13 May 2009 17:14:09 +0000 Subject: [PATCH] Add retain last login yesNo option. If configured to retain, workflow will determine if the last login would be removed from the login history and will skip deleting that entry. --- .../Workflow/Activity/CleanLoginHistory.pm | 101 ++++++++++++------ 1 file changed, 70 insertions(+), 31 deletions(-) diff --git a/lib/WebGUI/Workflow/Activity/CleanLoginHistory.pm b/lib/WebGUI/Workflow/Activity/CleanLoginHistory.pm index dd91ee6ba..5f9318f54 100644 --- a/lib/WebGUI/Workflow/Activity/CleanLoginHistory.pm +++ b/lib/WebGUI/Workflow/Activity/CleanLoginHistory.pm @@ -1,6 +1,5 @@ package WebGUI::Workflow::Activity::CleanLoginHistory; - =head1 LEGAL ------------------------------------------------------------------- @@ -17,6 +16,8 @@ package WebGUI::Workflow::Activity::CleanLoginHistory; use strict; use base 'WebGUI::Workflow::Activity'; +use DateTime; +use WebGUI::SQL; =head1 NAME @@ -28,15 +29,10 @@ Deletes some of the old cruft from the userLoginLog table. =head1 SYNOPSIS -See WebGUI::Workflow::Activity for details on how to use any activity. - -=head1 METHODS - -These methods are available from this class: +Clean up the userLoginLog for space using age and last login preservation rules =cut - #------------------------------------------------------------------- =head2 definition ( session, definition ) @@ -46,24 +42,31 @@ 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, "Workflow_Activity_CleanLoginHistory"); - push(@{$definition}, { - name=>$i18n->get("activityName"), - properties=> { - ageToDelete => { - fieldType=>"interval", - label=>$i18n->get("age to delete"), - defaultValue=>60 * 60 * 24 * 90, - hoverHelp=>$i18n->get("age to delete help") - } - } - }); - return $class->SUPER::definition($session,$definition); -} - + my $class = shift; + my $session = shift; + my $definition = shift; + my $i18n = WebGUI::International->new( $session, "Workflow_Activity_CleanLoginHistory" ); + push( + @{$definition}, { + name => $i18n->get("activityName"), + properties => { + ageToDelete => { + fieldType => "interval", + label => $i18n->get("age to delete"), + defaultValue => 60 * 60 * 24 * 90, + hoverHelp => $i18n->get("age to delete help") + }, + retainLastAlways => { + fieldType => "yesNo", + defaultValue => 0, + label => $i18n->get("retain last login is enabled"), + hoverHelp => $i18n->get("retain last login is enabled help") + }, + } + } + ); + return $class->SUPER::definition( $session, $definition ); +} ## end sub definition #------------------------------------------------------------------- @@ -74,13 +77,49 @@ See WebGUI::Workflow::Activity::execute() for details. =cut sub execute { - my $self = shift; - $self->session->db->write("delete from userLoginLog where timeStamp < ?", [(time()-($self->get("ageToDelete")))]); - return $self->COMPLETE; -} + my $self = shift; + my $db = $self->session->db; + my $time = DateTime->now->set_time_zone('UTC')->epoch; + my $epochTimeStamp = $time - ( $self->get("ageToDelete") ); + if ( not $self->get("retainLastAlways") ) { # Brutish clean-up + $db->write( "DELETE FROM userLoginLog WHERE timeStamp < ?", [$epochTimeStamp] ); + } + else { # Retain at least one login record for every user + + # Get only userIds for users with login information preceding ageToDelete + my $sth = $db->read( "SELECT DISTINCT userId FROM userLoginLog WHERE timeStamp < ? ORDER BY timeStamp", + [$epochTimeStamp] ); + + my $finishTime = time() + $self->getTTL; + + USERLOOP: while ( my (@userIdData) = $sth->array ) { + return $self->WAITING(1) if time() > $finishTime; + + my $userId = $userIdData[0]; + + my @userTimes + = $db->buildArray( "SELECT timeStamp FROM userLoginLog WHERE userId=? ORDER BY timeStamp desc", + [$userId] ); + + # Always preserve the most recent login, especially if it is older than ageToDelete. + shift @userTimes; + + # Only delete times older than ageToDelete (retain all recent records) + my @deleteTimes = (); + while ( my $ts = shift @userTimes ) { + push @deleteTimes, $ts if $ts < $epochTimeStamp; + } + + # Stop if there are no records preceding ageToDelete + next USERLOOP unless @deleteTimes; + + my $inTimes = WebGUI::SQL::quoteAndJoin( \@deleteTimes ); + $db->write( "DELETE FROM userLoginLog WHERE userId = ? AND timeStamp IN ($inTimes)", [$userId] ); + } ## end while ( my (@userIdData) ... + } ## end else [ if ( not $self->get("retainLastAlways"... + return $self->COMPLETE; +} ## end sub execute 1; - -